From 748fe4399f9194285a91ec8c09141e49a6b470b4 Mon Sep 17 00:00:00 2001 From: "Hailong.Liu" Date: Wed, 22 May 2024 16:03:28 +0800 Subject: [PATCH 01/60] HID: Use kvzalloc instead of kzalloc in hid_register_field() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function hid_register_field() might allocate more than 32k, which would use order-4 contiguous memory if the parameter usage exceeds 1024. However, after the system runs for a while, the memory can become heavily fragmented. This increases the likelihood of order-4 page allocation failure. Here’s the relevant log. [71553.093623]kworker/1: 0: page allocation failure: order:4, mode:0x40dc0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), nodemask=(null),cpuset=/,mems_allowed=0 [71553.093669]Workqueue: events uhid_device_add_worker [71553.093683]Call trace: [71553.093687]: dump_backtrace+0xf4/0x118 [71553.093696]: show_stack+0x18/0x24 [71553.093702]: dump_stack_lvl+0x60/0x7c [71553.093710]: dump_stack+0x18/0x3c [71553.093717]: warn_alloc+0xf4/0x174 [71553.093725]: __alloc_pages_slowpath+0x1ba0/0x1cac [71553.093732]: __alloc_pages+0x460/0x560 [71553.093738]: __kmalloc_large_node+0xbc/0x1f8 [71553.093746]: __kmalloc+0x144/0x254 [71553.093752]: hid_add_field+0x13c/0x308 [71553.093758]: hid_parser_main+0x250/0x298 [71553.093765]: hid_open_report+0x214/0x30c [71553.093771]: mt_probe+0x130/0x258 [71553.093778]: hid_device_probe+0x11c/0x1e4 [71553.093784]: really_probe+0xe4/0x388 [71553.093791]: __driver_probe_device+0xa0/0x12c [71553.093798]: driver_probe_device+0x44/0x214 [71553.093804]: __device_attach_driver+0xdc/0x124 [71553.093812]: bus_for_each_drv+0x88/0xec [71553.093818]: __device_attach+0x84/0x170 [71553.093824]: device_initial_probe+0x14/0x20 [71553.093831]: bus_probe_device+0x48/0xd0 [71553.093836]: device_add+0x248/0x928 [71553.093844]: hid_add_device+0xf8/0x1a4 [71553.093850]: uhid_device_add_worker+0x24/0x144 [71553.093857]: process_one_work+0x158/0x804 [71553.093865]: worker_thread+0x15c/0x494 [71553.093872]: kthread+0xf4/0x1e4 [71553.093880]: ret_from_fork+0x10/0x20 To fix the allocation failure, use kvzalloc() instead of kzalloc(). Signed-off-by: Hailong.Liu Acked-by: Barry Song Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b1fa0378e8f4..b49d4e2b7512 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -95,9 +95,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned return NULL; } - field = kzalloc((sizeof(struct hid_field) + - usages * sizeof(struct hid_usage) + - 3 * usages * sizeof(unsigned int)), GFP_KERNEL); + field = kvzalloc((sizeof(struct hid_field) + + usages * sizeof(struct hid_usage) + + 3 * usages * sizeof(unsigned int)), GFP_KERNEL); if (!field) return NULL; @@ -661,7 +661,7 @@ static void hid_free_report(struct hid_report *report) kfree(report->field_entries); for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); + kvfree(report->field[n]); kfree(report); } From 48144e83daba5619adaf0baf4fcea98082dce818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 24 May 2024 13:21:35 +0200 Subject: [PATCH 02/60] HID: uclogic: Support HUION devices with up to 20 buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HID descriptor for HUION tablets was limited to 13 buttons. However, there are devices with more buttons in their frames. So far, the device with more buttons released by HUION is the Huion Kamvas Pro 24 (GT-240, QHD) [1], with 20 buttons. Tweak the HID descriptor to support it. Link: https://gitlab.freedesktop.org/libinput/libinput/-/issues/989 [1] Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-rdesc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index b6dfdf6356a6..7cbd673747a5 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -689,10 +689,10 @@ const size_t uclogic_rdesc_v2_pen_template_size = 0xA0, /* Collection (Physical), */ \ 0x05, 0x09, /* Usage Page (Button), */ \ 0x19, 0x01, /* Usage Minimum (01h), */ \ - 0x29, 0x03, /* Usage Maximum (03h), */ \ - 0x95, 0x03, /* Report Count (3), */ \ + 0x29, 0x0A, /* Usage Maximum (0Ah), */ \ + 0x95, 0x0A, /* Report Count (10), */ \ 0x81, 0x02, /* Input (Variable), */ \ - 0x95, ((_size) * 8 - 45), \ + 0x95, ((_size) * 8 - 52), \ /* Report Count (padding), */ \ 0x81, 0x01, /* Input (Constant), */ \ 0xC0, /* End Collection, */ \ From 06483d251df678907b1d627d67b5464beb5358b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 24 May 2024 13:21:36 +0200 Subject: [PATCH 03/60] HID: uclogic: Use Rx and Ry for touch strips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, HUION devices use ABS_WHEEL as the usage for touch strips. There are 2 main issues with this approach: The first one is that the descriptor for touch rings (uclogic_rdesc_v2_frame_touch_ring_arr) also uses ABS_WHEEL. >From user-space it is impossible to know which device sends the events. The second one is that Wacom uses ABS_RX/ABS_RY to notify events from touch strips and user-space was designed to handle those axes. Change the usage of touch strips to Rx/Ry to fix both issues. Link: https://gitlab.freedesktop.org/libinput/libinput/-/issues/989 Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-rdesc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 7cbd673747a5..dfd74a043b39 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -789,7 +789,8 @@ const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[] = { 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x38, /* Usage (Wheel), */ + 0x09, 0x33, /* Usage (Rx), */ + 0x09, 0x34, /* Usage (Ry), */ 0x95, 0x01, /* Report Count (1), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x07, /* Logical Maximum (7), */ From 9ee76cd60025b61f12d8a0a21861c763c2b7674e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 25 May 2024 08:17:41 -0700 Subject: [PATCH 04/60] HID: intel-ish-hid: fix ishtp_wait_resume() kernel-doc Fix the 'make W=1' kernel-doc warning: drivers/hid/intel-ish-hid/ishtp/bus.c:853: warning: Function parameter or struct member 'dev' not described in 'ishtp_wait_resume' Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202311060843.dXENYlGc-lkp@intel.com/ Signed-off-by: Jeff Johnson Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 03d5601ce807..f3042c4b8710 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -844,6 +844,7 @@ EXPORT_SYMBOL(ishtp_device); /** * ishtp_wait_resume() - Wait for IPC resume + * @dev: ishtp device * * Wait for IPC resume * From 8bb9f9fa59ef9034d081e89978c5c1031fc850bd Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 25 May 2024 08:17:42 -0700 Subject: [PATCH 05/60] HID: intel-ish-hid: add MODULE_DESCRIPTION() Fix the 'make W=1' warning: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/intel-ish-hid/intel-ishtp.o Signed-off-by: Jeff Johnson Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index f3042c4b8710..cc76b295b632 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -932,4 +932,5 @@ static void __exit ishtp_bus_unregister(void) module_init(ishtp_bus_register); module_exit(ishtp_bus_unregister); +MODULE_DESCRIPTION("ISHTP bus driver"); MODULE_LICENSE("GPL"); From 09bae5876dde05410e62145f7e4c3be39011efff Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 31 May 2024 16:55:59 +0800 Subject: [PATCH 06/60] HID: nintendo: Remove some unused functions These functions are defined in the hid-nintendo.c file, but not called elsewhere, so delete these unused functions. drivers/hid/hid-nintendo.c:672:20: warning: unused function 'joycon_device_is_procon'. drivers/hid/hid-nintendo.c:682:20: warning: unused function 'joycon_device_is_snescon'. drivers/hid/hid-nintendo.c:687:20: warning: unused function 'joycon_device_is_gencon'. drivers/hid/hid-nintendo.c:692:20: warning: unused function 'joycon_device_is_n64con'. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=9265 Signed-off-by: Jiapeng Chong Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index b4a97803eca3..be7f7e47d65f 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -658,7 +658,6 @@ struct joycon_ctlr { (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \ ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO) - /* * Controller device helpers * @@ -669,31 +668,11 @@ struct joycon_ctlr { * These helpers are most useful early during the HID probe or in conjunction * with the capability helpers below. */ -static inline bool joycon_device_is_procon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON; -} - static inline bool joycon_device_is_chrggrip(struct joycon_ctlr *ctlr) { return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP; } -static inline bool joycon_device_is_snescon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON; -} - -static inline bool joycon_device_is_gencon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_GENCON; -} - -static inline bool joycon_device_is_n64con(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON; -} - /* * Controller type helpers * From b81881b9c10e1f5eafc02df026663b824610d537 Mon Sep 17 00:00:00 2001 From: Danny Kaehn Date: Wed, 5 Jun 2024 18:12:45 -0500 Subject: [PATCH 07/60] HID: usbhid: Share USB device firmware node with child HID device USB HID core now shares its fwnode with its child HID device. Since there can only be one HID device on a USB interface, it is redundant to specify a hid node under the USB device. This allows usb HID device drivers to be described in firmware and make use of device properties. Signed-off-by: Danny Kaehn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240605-cp2112-dt-v11-2-d55f0f945a62@plexus.com Signed-off-by: Benjamin Tissoires --- drivers/hid/usbhid/hid-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index a90ed2ceae84..cb687ea7325c 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1374,6 +1375,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * hid->hiddev_report_event = hiddev_report_event; #endif hid->dev.parent = &intf->dev; + device_set_node(&hid->dev, dev_fwnode(&intf->dev)); hid->bus = BUS_USB; hid->vendor = le16_to_cpu(dev->descriptor.idVendor); hid->product = le16_to_cpu(dev->descriptor.idProduct); From fae5d8433db235801c3915be63a0325d444d0593 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 4 Jun 2024 07:20:47 -0700 Subject: [PATCH 08/60] HID: letsketch: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-letsketch.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20240604-md-hid-letsketch-v1-1-ff38ae7b4cb0@quicinc.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-letsketch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c index 97f047f18136..229820fda960 100644 --- a/drivers/hid/hid-letsketch.c +++ b/drivers/hid/hid-letsketch.c @@ -319,4 +319,5 @@ static struct hid_driver letsketch_driver = { module_hid_driver(letsketch_driver); MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Driver for the LetSketch / VSON WP9620N drawing tablet"); MODULE_LICENSE("GPL"); From e52a7d0562d89459c12fe17ed78cd2f40c854e10 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 4 Jun 2024 07:33:01 -0700 Subject: [PATCH 09/60] HID: lg-g15: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lg-g15.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20240604-md-hid-lg-g15-v1-1-265b094db089@quicinc.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-lg-g15.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c index acbec1dcf196..53e7b90f9cc3 100644 --- a/drivers/hid/hid-lg-g15.c +++ b/drivers/hid/hid-lg-g15.c @@ -954,4 +954,5 @@ static struct hid_driver lg_g15_driver = { module_hid_driver(lg_g15_driver); MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("HID driver for gaming keys on Logitech gaming keyboards"); MODULE_LICENSE("GPL"); From ece3941821cf599af6454d8111b0169a29f08c4d Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 4 Jun 2024 08:34:01 -0700 Subject: [PATCH 10/60] HID: logitech-dj: add missing MODULE_DESCRIPTION() macro make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-logitech-dj.o Add the missing invocation of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240604-md-hid-logitech-dj-v1-1-560f6b3cb54b@quicinc.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-logitech-dj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 3c3c497b6b91..dfa4e3d1a3b3 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -2045,6 +2045,7 @@ static struct hid_driver logi_djreceiver_driver = { module_hid_driver(logi_djreceiver_driver); +MODULE_DESCRIPTION("HID driver for Logitech receivers"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Logitech"); MODULE_AUTHOR("Nestor Lopez Casado"); From 9d262f35b1155d6f56b6fd1dc054ec218e42696b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 4 Jun 2024 15:10:23 -0700 Subject: [PATCH 11/60] HID: add missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-a4tech.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-apple.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-aureal.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-belkin.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-betopff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-bigbenff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-cherry.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-chicony.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-cypress.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-dr.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-emsff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-elecom.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-elo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-evision.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ezkey.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-vivaldi-common.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-google-hammer.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-google-stadiaff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-gyration.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-holtek-kbd.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-holtek-mouse.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ite.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kensington.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-keytouch.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kye.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lcpower.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lenovo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-logitech.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-magicmouse.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-maltron.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-mf.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-megaworld.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-microsoft.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-monterey.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ntrig.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ortek.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-prodikeys.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-pl.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-petalynx.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-primax.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-razer.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-redragon.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-retrode.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-saitek.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-samsung.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-semitek.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-sjoy.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-sony.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-speedlink.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-steam.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-steelseries.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-sunplus.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-gaff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-tmff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-tivo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-topseed.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-twinhan.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-uclogic.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-xinmo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-zpff.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-zydacron.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-viewsonic.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-waltop.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-winwing.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Note: All HID drivers that had explicit entries in the MAINTAINERS file were fixed individually. This patch fixes all remaining HID drivers that fall under the generic "HID CORE LAYER" entry in the MAINTAINERS file. Almost all descriptions were taken from the header comment in each file. Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240604-md-hid-misc-v1-1-4f9560796f3c@quicinc.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-a4tech.c | 1 + drivers/hid/hid-apple.c | 1 + drivers/hid/hid-aureal.c | 1 + drivers/hid/hid-belkin.c | 1 + drivers/hid/hid-betopff.c | 1 + drivers/hid/hid-bigbenff.c | 1 + drivers/hid/hid-cherry.c | 1 + drivers/hid/hid-chicony.c | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-cypress.c | 1 + drivers/hid/hid-dr.c | 1 + drivers/hid/hid-elecom.c | 1 + drivers/hid/hid-elo.c | 1 + drivers/hid/hid-emsff.c | 1 + drivers/hid/hid-evision.c | 1 + drivers/hid/hid-ezkey.c | 1 + drivers/hid/hid-gaff.c | 1 + drivers/hid/hid-google-hammer.c | 1 + drivers/hid/hid-google-stadiaff.c | 1 + drivers/hid/hid-gyration.c | 1 + drivers/hid/hid-holtek-kbd.c | 1 + drivers/hid/hid-lg.c | 1 + drivers/hid/hid-magicmouse.c | 1 + drivers/hid/hid-maltron.c | 1 + drivers/hid/hid-megaworld.c | 1 + drivers/hid/hid-mf.c | 1 + drivers/hid/hid-microsoft.c | 1 + drivers/hid/hid-monterey.c | 1 + drivers/hid/hid-ntrig.c | 1 + drivers/hid/hid-ortek.c | 1 + drivers/hid/hid-petalynx.c | 1 + drivers/hid/hid-pl.c | 1 + drivers/hid/hid-primax.c | 1 + drivers/hid/hid-prodikeys.c | 1 + drivers/hid/hid-razer.c | 1 + drivers/hid/hid-redragon.c | 1 + drivers/hid/hid-retrode.c | 1 + drivers/hid/hid-saitek.c | 1 + drivers/hid/hid-samsung.c | 1 + drivers/hid/hid-semitek.c | 1 + drivers/hid/hid-sjoy.c | 1 + drivers/hid/hid-sony.c | 1 + drivers/hid/hid-speedlink.c | 1 + drivers/hid/hid-steam.c | 1 + drivers/hid/hid-steelseries.c | 1 + drivers/hid/hid-sunplus.c | 1 + drivers/hid/hid-tivo.c | 1 + drivers/hid/hid-tmff.c | 1 + drivers/hid/hid-topseed.c | 1 + drivers/hid/hid-twinhan.c | 1 + drivers/hid/hid-uclogic-core.c | 1 + drivers/hid/hid-viewsonic.c | 1 + drivers/hid/hid-vivaldi-common.c | 1 + drivers/hid/hid-waltop.c | 1 + drivers/hid/hid-xinmo.c | 1 + drivers/hid/hid-zpff.c | 1 + drivers/hid/hid-zydacron.c | 1 + 57 files changed, 57 insertions(+) diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 2cbc32dda7f7..54bfaf61182b 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c @@ -163,4 +163,5 @@ static struct hid_driver a4_driver = { }; module_hid_driver(a4_driver); +MODULE_DESCRIPTION("HID driver for some a4tech \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index bd022e004356..37280f558157 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -1091,4 +1091,5 @@ static struct hid_driver apple_driver = { }; module_hid_driver(apple_driver); +MODULE_DESCRIPTION("Apple USB HID quirks support for Linux"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c index ac8946f80e22..cf1a562d8523 100644 --- a/drivers/hid/hid-aureal.c +++ b/drivers/hid/hid-aureal.c @@ -41,4 +41,5 @@ static struct hid_driver aureal_driver = { }; module_hid_driver(aureal_driver); +MODULE_DESCRIPTION("HID driver for Aureal Cy se W-01RN USB_V3.1 devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c index fc0b3bb383cc..75aaed35ee9f 100644 --- a/drivers/hid/hid-belkin.c +++ b/drivers/hid/hid-belkin.c @@ -85,4 +85,5 @@ static struct hid_driver belkin_driver = { }; module_hid_driver(belkin_driver); +MODULE_DESCRIPTION("HID driver for some belkin \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c index 25ed7b9a917e..a6d5f030d023 100644 --- a/drivers/hid/hid-betopff.c +++ b/drivers/hid/hid-betopff.c @@ -162,4 +162,5 @@ static struct hid_driver betop_driver = { }; module_hid_driver(betop_driver); +MODULE_DESCRIPTION("Force feedback support for Betop based devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c index a02cb517b4c4..be17af3d9c0c 100644 --- a/drivers/hid/hid-bigbenff.c +++ b/drivers/hid/hid-bigbenff.c @@ -490,4 +490,5 @@ static struct hid_driver bigben_driver = { }; module_hid_driver(bigben_driver); +MODULE_DESCRIPTION("LED & force feedback support for BigBen Interactive"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index 6a71187b5cf6..549c73b05b8d 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -68,4 +68,5 @@ static struct hid_driver ch_driver = { }; module_hid_driver(ch_driver); +MODULE_DESCRIPTION("HID driver for some cherry \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index f04d2aa23efe..99954c6b3242 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -152,4 +152,5 @@ static struct hid_driver ch_driver = { }; module_hid_driver(ch_driver); +MODULE_DESCRIPTION("HID driver for some chicony \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b1fa0378e8f4..3ef169a6c903 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -3025,4 +3025,5 @@ module_exit(hid_exit); MODULE_AUTHOR("Andreas Gal"); MODULE_AUTHOR("Vojtech Pavlik"); MODULE_AUTHOR("Jiri Kosina"); +MODULE_DESCRIPTION("HID support for Linux"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index b88f889b3932..b952b235e70a 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -176,4 +176,5 @@ static struct hid_driver cp_driver = { }; module_hid_driver(cp_driver); +MODULE_DESCRIPTION("HID driver for some cypress \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index 947f19f8685f..c88224a96e9e 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -316,4 +316,5 @@ static struct hid_driver dr_driver = { }; module_hid_driver(dr_driver); +MODULE_DESCRIPTION("Force feedback support for DragonRise Inc. game controllers"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 4fa45ee77503..5973a3bab29f 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -136,4 +136,5 @@ static struct hid_driver elecom_driver = { }; module_hid_driver(elecom_driver); +MODULE_DESCRIPTION("HID driver for ELECOM devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 2876cb6a7dca..cf17bdd14d9c 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -313,4 +313,5 @@ static void __exit elo_driver_exit(void) module_exit(elo_driver_exit); MODULE_AUTHOR("Jiri Slaby "); +MODULE_DESCRIPTION("HID driver for ELO usb touchscreen 4000/4500"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c index c34f2e5a049f..60bfb6a924d7 100644 --- a/drivers/hid/hid-emsff.c +++ b/drivers/hid/hid-emsff.c @@ -144,5 +144,6 @@ static struct hid_driver ems_driver = { }; module_hid_driver(ems_driver); +MODULE_DESCRIPTION("Force feedback support for EMS Trio Linker Plus II"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-evision.c b/drivers/hid/hid-evision.c index ef6b4b435215..bb5997078491 100644 --- a/drivers/hid/hid-evision.c +++ b/drivers/hid/hid-evision.c @@ -50,4 +50,5 @@ static struct hid_driver evision_driver = { }; module_hid_driver(evision_driver); +MODULE_DESCRIPTION("HID driver for EVision devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c index d14f91d78c96..0e28bc0b87fa 100644 --- a/drivers/hid/hid-ezkey.c +++ b/drivers/hid/hid-ezkey.c @@ -75,4 +75,5 @@ static struct hid_driver ez_driver = { }; module_hid_driver(ez_driver); +MODULE_DESCRIPTION("HID driver for some ezkey \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index ecbd3995a4eb..c6db8b6cc8ee 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -169,4 +169,5 @@ static struct hid_driver ga_driver = { }; module_hid_driver(ga_driver); +MODULE_DESCRIPTION("Force feedback support for GreenAsia (Product ID 0x12) based devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index 25331695ae32..6e4ebc349e45 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -641,4 +641,5 @@ static void __exit hammer_exit(void) } module_exit(hammer_exit); +MODULE_DESCRIPTION("HID driver for Google Hammer device."); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-google-stadiaff.c b/drivers/hid/hid-google-stadiaff.c index 3731575562ab..6b38d2421d3d 100644 --- a/drivers/hid/hid-google-stadiaff.c +++ b/drivers/hid/hid-google-stadiaff.c @@ -155,4 +155,5 @@ static struct hid_driver stadia_driver = { }; module_hid_driver(stadia_driver); +MODULE_DESCRIPTION("Google Stadia controller rumble support."); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c index b99a611479b3..6606b57abe83 100644 --- a/drivers/hid/hid-gyration.c +++ b/drivers/hid/hid-gyration.c @@ -87,4 +87,5 @@ static struct hid_driver gyration_driver = { }; module_hid_driver(gyration_driver); +MODULE_DESCRIPTION("HID driver for some gyration \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c index b346d68a06f5..1f014ac54e14 100644 --- a/drivers/hid/hid-holtek-kbd.c +++ b/drivers/hid/hid-holtek-kbd.c @@ -180,4 +180,5 @@ static struct hid_driver holtek_kbd_driver = { }; module_hid_driver(holtek_kbd_driver); +MODULE_DESCRIPTION("HID driver for Holtek keyboard"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index fb3f7258009c..cfe2f4f6e93f 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -942,4 +942,5 @@ module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO); MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically"); #endif +MODULE_DESCRIPTION("HID driver for some logitech \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index a46ff4e8b99f..2eb285b97fc0 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -968,4 +968,5 @@ static struct hid_driver magicmouse_driver = { }; module_hid_driver(magicmouse_driver); +MODULE_DESCRIPTION("Apple \"Magic\" Wireless Mouse driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-maltron.c b/drivers/hid/hid-maltron.c index dcd6db6a646e..caba0def938c 100644 --- a/drivers/hid/hid-maltron.c +++ b/drivers/hid/hid-maltron.c @@ -162,4 +162,5 @@ static struct hid_driver maltron_driver = { }; module_hid_driver(maltron_driver); +MODULE_DESCRIPTION("HID driver for Maltron L90"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-megaworld.c b/drivers/hid/hid-megaworld.c index 599657863cb9..0476d7d16e7f 100644 --- a/drivers/hid/hid-megaworld.c +++ b/drivers/hid/hid-megaworld.c @@ -122,4 +122,5 @@ static struct hid_driver mwctrl_driver = { }; module_hid_driver(mwctrl_driver); +MODULE_DESCRIPTION("Vibration support for Mega World controllers"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-mf.c b/drivers/hid/hid-mf.c index 92d7ecd41a78..49a4052a1496 100644 --- a/drivers/hid/hid-mf.c +++ b/drivers/hid/hid-mf.c @@ -166,4 +166,5 @@ static struct hid_driver mf_driver = { }; module_hid_driver(mf_driver); +MODULE_DESCRIPTION("Force feedback support for Mayflash game controller adapters."); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 9345e2bfd56e..4cf0fcddb379 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -475,4 +475,5 @@ static struct hid_driver ms_driver = { }; module_hid_driver(ms_driver); +MODULE_DESCRIPTION("HID driver for some microsoft \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index c63f9f1e61b8..989681f73d77 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -62,4 +62,5 @@ static struct hid_driver mr_driver = { }; module_hid_driver(mr_driver); +MODULE_DESCRIPTION("HID driver for some monterey \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index b5d26f03fe6b..2738ce947434 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -1029,4 +1029,5 @@ static struct hid_driver ntrig_driver = { }; module_hid_driver(ntrig_driver); +MODULE_DESCRIPTION("HID driver for N-Trig touchscreens"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c index 9a4770d79c64..99e3b06a8331 100644 --- a/drivers/hid/hid-ortek.c +++ b/drivers/hid/hid-ortek.c @@ -51,4 +51,5 @@ static struct hid_driver ortek_driver = { }; module_hid_driver(ortek_driver); +MODULE_DESCRIPTION("HID driver for Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index ea0af9f7ad90..5e47634bb07d 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -102,4 +102,5 @@ static struct hid_driver pl_driver = { }; module_hid_driver(pl_driver); +MODULE_DESCRIPTION("HID driver for some petalynx \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 93fb07ec3180..3c8827081dea 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -219,4 +219,5 @@ static struct hid_driver pl_driver = { }; module_hid_driver(pl_driver); +MODULE_DESCRIPTION("Force feedback support for PantherLord/GreenAsia based devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c index 1e6413d07cae..e44d79dff8de 100644 --- a/drivers/hid/hid-primax.c +++ b/drivers/hid/hid-primax.c @@ -70,4 +70,5 @@ static struct hid_driver px_driver = { module_hid_driver(px_driver); MODULE_AUTHOR("Terry Lambert "); +MODULE_DESCRIPTION("HID driver for primax and similar keyboards with in-band modifiers"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index a593ed62c969..757361593e52 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -862,4 +862,5 @@ static struct hid_driver pk_driver = { }; module_hid_driver(pk_driver); +MODULE_DESCRIPTION("HID driver for the Prodikeys PC-MIDI Keyboard"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-razer.c b/drivers/hid/hid-razer.c index 740df148b0ef..7f48258c61f7 100644 --- a/drivers/hid/hid-razer.c +++ b/drivers/hid/hid-razer.c @@ -122,4 +122,5 @@ static struct hid_driver razer_driver = { module_hid_driver(razer_driver); MODULE_AUTHOR("Jelle van der Waa "); +MODULE_DESCRIPTION("HID driver for gaming keys on Razer Blackwidow gaming keyboards"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-redragon.c b/drivers/hid/hid-redragon.c index 73c9d4c4fa34..07d803513f27 100644 --- a/drivers/hid/hid-redragon.c +++ b/drivers/hid/hid-redragon.c @@ -59,4 +59,5 @@ static struct hid_driver redragon_driver = { module_hid_driver(redragon_driver); +MODULE_DESCRIPTION("HID driver for Redragon keyboards"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-retrode.c b/drivers/hid/hid-retrode.c index 6a08e25aa296..7997627fdccc 100644 --- a/drivers/hid/hid-retrode.c +++ b/drivers/hid/hid-retrode.c @@ -94,4 +94,5 @@ static struct hid_driver retrode_driver = { module_hid_driver(retrode_driver); +MODULE_DESCRIPTION("HID driver for Retrode 2 controller adapter and plug-in extensions"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c index b84e975977c4..85ac8def368f 100644 --- a/drivers/hid/hid-saitek.c +++ b/drivers/hid/hid-saitek.c @@ -204,4 +204,5 @@ static struct hid_driver saitek_driver = { }; module_hid_driver(saitek_driver); +MODULE_DESCRIPTION("HID driver for Saitek devices."); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 08fb25b8459a..d4e27142245c 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c @@ -561,4 +561,5 @@ static struct hid_driver samsung_driver = { }; module_hid_driver(samsung_driver); +MODULE_DESCRIPTION("HID driver for some samsung \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-semitek.c b/drivers/hid/hid-semitek.c index ba6607d5e051..710766f6839d 100644 --- a/drivers/hid/hid-semitek.c +++ b/drivers/hid/hid-semitek.c @@ -37,4 +37,5 @@ static struct hid_driver semitek_driver = { }; module_hid_driver(semitek_driver); +MODULE_DESCRIPTION("HID driver for Semitek keyboards"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index 49971be7c3ff..d3a777f52a3f 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -168,6 +168,7 @@ static struct hid_driver sjoy_driver = { }; module_hid_driver(sjoy_driver); +MODULE_DESCRIPTION("Force feedback support for SmartJoy PLUS PS2->USB adapter"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jussi Kivilinna"); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 5a07a91a89ae..eac75f98f08a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2308,4 +2308,5 @@ static void __exit sony_exit(void) module_init(sony_init); module_exit(sony_exit); +MODULE_DESCRIPTION("HID driver for Sony / PS2 / PS3 / PS4 BD devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c index 9e75f1aae0ca..22ee078c42c6 100644 --- a/drivers/hid/hid-speedlink.c +++ b/drivers/hid/hid-speedlink.c @@ -75,4 +75,5 @@ static struct hid_driver speedlink_driver = { }; module_hid_driver(speedlink_driver); +MODULE_DESCRIPTION("HID driver for Speedlink Vicious and Divine Cezanne (USB mouse)"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index f166188c21ec..bfba204fc45e 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -45,6 +45,7 @@ #include #include "hid-ids.h" +MODULE_DESCRIPTION("HID driver for Valve Steam Controller"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rodrigo Rivas Costa "); diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index b3edadf42d6d..2154e14f55f1 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -662,6 +662,7 @@ static struct hid_driver steelseries_driver = { }; module_hid_driver(steelseries_driver); +MODULE_DESCRIPTION("HID driver for Steelseries devices"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Bastien Nocera "); MODULE_AUTHOR("Simon Wood "); diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index aa2855c2ed4e..f32e60d4420f 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -62,4 +62,5 @@ static struct hid_driver sp_driver = { }; module_hid_driver(sp_driver); +MODULE_DESCRIPTION("HID driver for some sunplus \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-tivo.c b/drivers/hid/hid-tivo.c index 68eb08b63945..827bf67abeb9 100644 --- a/drivers/hid/hid-tivo.c +++ b/drivers/hid/hid-tivo.c @@ -73,5 +73,6 @@ static struct hid_driver tivo_driver = { }; module_hid_driver(tivo_driver); +MODULE_DESCRIPTION("HID driver for TiVo Slide Bluetooth remote"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 4040cd98dafe..fcd859aa3a8c 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -265,4 +265,5 @@ static struct hid_driver tm_driver = { }; module_hid_driver(tm_driver); +MODULE_DESCRIPTION("Force feedback support for various HID compliant devices by ThrustMaster"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 2125327b8de1..645e36cd83a6 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -78,4 +78,5 @@ static struct hid_driver ts_driver = { }; module_hid_driver(ts_driver); +MODULE_DESCRIPTION("HID driver for TopSeed Cyberlink remote"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c index 14af794146c0..0ef5194085b2 100644 --- a/drivers/hid/hid-twinhan.c +++ b/drivers/hid/hid-twinhan.c @@ -131,4 +131,5 @@ static struct hid_driver twinhan_driver = { }; module_hid_driver(twinhan_driver); +MODULE_DESCRIPTION("HID driver for TwinHan IR remote control"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index ad74cbc9a0aa..02520824ce77 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -567,6 +567,7 @@ module_hid_driver(uclogic_driver); MODULE_AUTHOR("Martin Rusko"); MODULE_AUTHOR("Nikolai Kondrashov"); +MODULE_DESCRIPTION("HID driver for UC-Logic devices not fully compliant with HID standard"); MODULE_LICENSE("GPL"); #ifdef CONFIG_HID_KUNIT_TEST diff --git a/drivers/hid/hid-viewsonic.c b/drivers/hid/hid-viewsonic.c index 8024b1d370e2..668c2adb77b6 100644 --- a/drivers/hid/hid-viewsonic.c +++ b/drivers/hid/hid-viewsonic.c @@ -102,4 +102,5 @@ static struct hid_driver viewsonic_driver = { }; module_hid_driver(viewsonic_driver); +MODULE_DESCRIPTION("HID driver for ViewSonic devices not fully compliant with HID standard"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-vivaldi-common.c b/drivers/hid/hid-vivaldi-common.c index b0af2be94895..bf734055d4b6 100644 --- a/drivers/hid/hid-vivaldi-common.c +++ b/drivers/hid/hid-vivaldi-common.c @@ -138,4 +138,5 @@ const struct attribute_group *vivaldi_attribute_groups[] = { }; EXPORT_SYMBOL_GPL(vivaldi_attribute_groups); +MODULE_DESCRIPTION("Helpers for ChromeOS HID Vivaldi keyboards"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c index bc355b1a5b30..1e590c61eef5 100644 --- a/drivers/hid/hid-waltop.c +++ b/drivers/hid/hid-waltop.c @@ -742,4 +742,5 @@ static struct hid_driver waltop_driver = { }; module_hid_driver(waltop_driver); +MODULE_DESCRIPTION("HID driver for Waltop devices not fully compliant with HID standard"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-xinmo.c b/drivers/hid/hid-xinmo.c index 5c2860a9d8c9..66b8bfb6e647 100644 --- a/drivers/hid/hid-xinmo.c +++ b/drivers/hid/hid-xinmo.c @@ -56,4 +56,5 @@ static struct hid_driver xinmo_driver = { }; module_hid_driver(xinmo_driver); +MODULE_DESCRIPTION("HID driver for Xin-Mo devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index 3abaca045869..aacf7f137b18 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -138,4 +138,5 @@ static struct hid_driver zp_driver = { }; module_hid_driver(zp_driver); +MODULE_DESCRIPTION("Force feedback support for Zeroplus based devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c index 0d003caee113..998a3db19c1f 100644 --- a/drivers/hid/hid-zydacron.c +++ b/drivers/hid/hid-zydacron.c @@ -205,4 +205,5 @@ static struct hid_driver zc_driver = { }; module_hid_driver(zc_driver); +MODULE_DESCRIPTION("HID driver for zydacron remote control"); MODULE_LICENSE("GPL"); From 146a06a0d225cae240065233fd168fb0b95a10ff Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:13 +0200 Subject: [PATCH 12/60] HID: rename struct hid_bpf_ops into hid_ops Those operations are the ones from HID, not HID-BPF, and I'd like to reuse hid_bpf_ops as the user facing struct_ops API. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-1-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 22 +++++++++++----------- drivers/hid/hid-core.c | 6 +++--- include/linux/hid_bpf.h | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 10289f44d0cc..55c9f82fdef0 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -21,8 +21,8 @@ #include "hid_bpf_dispatch.h" #include "entrypoints/entrypoints.lskel.h" -struct hid_bpf_ops *hid_bpf_ops; -EXPORT_SYMBOL(hid_bpf_ops); +struct hid_ops *hid_ops; +EXPORT_SYMBOL(hid_ops); /** * hid_bpf_device_event - Called whenever an event is coming in from the device @@ -284,13 +284,13 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) struct device *dev; int err, fd; - if (!hid_bpf_ops) + if (!hid_ops) return -EINVAL; if ((flags & ~HID_BPF_FLAG_MASK)) return -EINVAL; - dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id); + dev = bus_find_device(hid_ops->bus_type, NULL, &hid_id, device_match_id); if (!dev) return -EINVAL; @@ -335,10 +335,10 @@ hid_bpf_allocate_context(unsigned int hid_id) struct hid_bpf_ctx_kern *ctx_kern = NULL; struct device *dev; - if (!hid_bpf_ops) + if (!hid_ops) return NULL; - dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id); + dev = bus_find_device(hid_ops->bus_type, NULL, &hid_id, device_match_id); if (!dev) return NULL; @@ -386,7 +386,7 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, u32 report_len; /* check arguments */ - if (!ctx || !hid_bpf_ops || !buf) + if (!ctx || !hid_ops || !buf) return -EINVAL; switch (rtype) { @@ -404,7 +404,7 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, hdev = (struct hid_device *)ctx->hid; /* discard const */ report_enum = hdev->report_enum + rtype; - report = hid_bpf_ops->hid_get_report(report_enum, buf); + report = hid_ops->hid_get_report(report_enum, buf); if (!report) return -EINVAL; @@ -459,7 +459,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, if (!dma_data) return -ENOMEM; - ret = hid_bpf_ops->hid_hw_raw_request(hdev, + ret = hid_ops->hid_hw_raw_request(hdev, dma_data[0], dma_data, size, @@ -501,7 +501,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) if (!dma_data) return -ENOMEM; - ret = hid_bpf_ops->hid_hw_output_report(hdev, + ret = hid_ops->hid_hw_output_report(hdev, dma_data, size); @@ -534,7 +534,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf hdev = (struct hid_device *)ctx->hid; /* discard const */ - return hid_bpf_ops->hid_input_report(hdev, type, buf, size, 0); + return hid_ops->hid_input_report(hdev, type, buf, size, 0); } __bpf_kfunc_end_defs(); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 74efda212c55..aed8850a4d01 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2970,7 +2970,7 @@ int hid_check_keys_pressed(struct hid_device *hid) EXPORT_SYMBOL_GPL(hid_check_keys_pressed); #ifdef CONFIG_HID_BPF -static struct hid_bpf_ops hid_ops = { +static struct hid_ops __hid_ops = { .hid_get_report = hid_get_report, .hid_hw_raw_request = hid_hw_raw_request, .hid_hw_output_report = hid_hw_output_report, @@ -2991,7 +2991,7 @@ static int __init hid_init(void) } #ifdef CONFIG_HID_BPF - hid_bpf_ops = &hid_ops; + hid_ops = &__hid_ops; #endif ret = hidraw_init(); @@ -3010,7 +3010,7 @@ err: static void __exit hid_exit(void) { #ifdef CONFIG_HID_BPF - hid_bpf_ops = NULL; + hid_ops = NULL; #endif hid_debug_exit(); hidraw_exit(); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index eec2592dec12..a66103618e6e 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -97,7 +97,7 @@ enum hid_bpf_prog_type { struct hid_report_enum; -struct hid_bpf_ops { +struct hid_ops { struct hid_report *(*hid_get_report)(struct hid_report_enum *report_enum, const u8 *data); int (*hid_hw_raw_request)(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, @@ -110,7 +110,7 @@ struct hid_bpf_ops { const struct bus_type *bus_type; }; -extern struct hid_bpf_ops *hid_bpf_ops; +extern struct hid_ops *hid_ops; struct hid_bpf_prog_list { u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV]; From 99b40bf8053fa261d368ef78848961c04aa93c74 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:14 +0200 Subject: [PATCH 13/60] HID: bpf: add hid_get/put_device() helpers no code change, but this way we reduce code duplication and we can export it later. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-2-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 47 +++++++++++++++++------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 55c9f82fdef0..c8bb79ce2354 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -150,6 +150,25 @@ static int device_match_id(struct device *dev, const void *id) return hdev->id == *(int *)id; } +static 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); +} + +static 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; @@ -281,20 +300,14 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) { struct hid_device *hdev; struct bpf_prog *prog; - struct device *dev; int err, fd; - if (!hid_ops) - return -EINVAL; - if ((flags & ~HID_BPF_FLAG_MASK)) return -EINVAL; - dev = bus_find_device(hid_ops->bus_type, NULL, &hid_id, device_match_id); - if (!dev) - return -EINVAL; - - hdev = to_hid_device(dev); + hdev = hid_get_device(hid_id); + if (IS_ERR(hdev)) + return PTR_ERR(hdev); /* * take a ref on the prog itself, it will be released @@ -317,7 +330,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) out_prog_put: bpf_prog_put(prog); out_dev_put: - put_device(dev); + hid_put_device(hdev); return err; } @@ -333,20 +346,14 @@ hid_bpf_allocate_context(unsigned int hid_id) { struct hid_device *hdev; struct hid_bpf_ctx_kern *ctx_kern = NULL; - struct device *dev; - if (!hid_ops) + hdev = hid_get_device(hid_id); + if (IS_ERR(hdev)) return NULL; - dev = bus_find_device(hid_ops->bus_type, NULL, &hid_id, device_match_id); - if (!dev) - return NULL; - - hdev = to_hid_device(dev); - ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL); if (!ctx_kern) { - put_device(dev); + hid_put_device(hdev); return NULL; } @@ -373,7 +380,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx) kfree(ctx_kern); /* get_device() is called by bus_find_device() */ - put_device(&hid->dev); + hid_put_device(hid); } static int From ebc0d8093e8c97de459615438edefad1a4ac352c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:15 +0200 Subject: [PATCH 14/60] HID: bpf: implement HID-BPF through bpf_struct_ops We do this implementation in several steps to not have the CI failing: - first (this patch), we add struct_ops while keeping the existing infra available - then we change the selftests, the examples and the existing in-tree HID-BPF programs - then we remove the existing trace points making old HID-BPF obsolete There are a few advantages of struct_ops over tracing: - compatibility with sleepable programs (for hid_hw_raw_request() in a later patch) - a lot simpler in the kernel: it's a simple rcu protected list - we can add more parameters to the function called without much trouble - the "attach" is now generic through BPF-core: the caller just needs to set hid_id and flags before calling __load(). - all the BPF tough part is not handled in BPF-core through generic processing - hid_bpf_ctx is now only writable where it needs be Acked-by: Alexei Starovoitov Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-3-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/Makefile | 2 +- drivers/hid/bpf/hid_bpf_dispatch.c | 52 +++++- drivers/hid/bpf/hid_bpf_dispatch.h | 4 + drivers/hid/bpf/hid_bpf_jmp_table.c | 3 + drivers/hid/bpf/hid_bpf_struct_ops.c | 252 +++++++++++++++++++++++++++ include/linux/hid_bpf.h | 61 ++++++- 6 files changed, 365 insertions(+), 9 deletions(-) create mode 100644 drivers/hid/bpf/hid_bpf_struct_ops.c diff --git a/drivers/hid/bpf/Makefile b/drivers/hid/bpf/Makefile index cf55120cf7d6..1cb3f31e9335 100644 --- a/drivers/hid/bpf/Makefile +++ b/drivers/hid/bpf/Makefile @@ -8,4 +8,4 @@ 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_jmp_table.o +hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_jmp_table.o hid_bpf_struct_ops.o diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index c8bb79ce2354..7216c3c7713d 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -58,6 +58,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type }, .data = hdev->bpf.device_data, }; + struct hid_bpf_ops *e; int ret; if (type >= HID_REPORT_TYPES) @@ -70,9 +71,25 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type 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); + if (ret < 0) { + rcu_read_unlock(); + return ERR_PTR(ret); + } + + if (ret) + ctx_kern.ctx.retval = ret; + } + } + rcu_read_unlock(); + ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern); if (ret < 0) return ERR_PTR(ret); + ret = ctx_kern.ctx.retval; if (ret) { if (ret > ctx_kern.ctx.allocated_size) @@ -122,7 +139,10 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s memcpy(ctx_kern.data, rdesc, min_t(unsigned int, *size, HID_MAX_DESCRIPTOR_SIZE)); - ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern); + if (hdev->bpf.rdesc_ops) + ret = hdev->bpf.rdesc_ops->hid_rdesc_fixup(&ctx_kern.ctx); + else + ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern); if (ret < 0) goto ignore_bpf; @@ -150,7 +170,7 @@ static int device_match_id(struct device *dev, const void *id) return hdev->id == *(int *)id; } -static struct hid_device *hid_get_device(unsigned int hid_id) +struct hid_device *hid_get_device(unsigned int hid_id) { struct device *dev; @@ -164,7 +184,7 @@ static struct hid_device *hid_get_device(unsigned int hid_id) return to_hid_device(dev); } -static void hid_put_device(struct hid_device *hid) +void hid_put_device(struct hid_device *hid) { put_device(&hid->dev); } @@ -205,7 +225,7 @@ static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size return 0; } -static int hid_bpf_allocate_event_data(struct hid_device *hdev) +int hid_bpf_allocate_event_data(struct hid_device *hdev) { /* hdev->bpf.device_data is already allocated, abort */ if (hdev->bpf.device_data) @@ -592,14 +612,22 @@ static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { int hid_bpf_connect_device(struct hid_device *hdev) { - struct hid_bpf_prog_list *prog_list; + bool need_to_allocate = false; + struct hid_bpf_ops *e; rcu_read_lock(); - prog_list = rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT]); + list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) { + if (e->hid_device_event) { + need_to_allocate = true; + break; + } + } + if (rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT])) + need_to_allocate = true; rcu_read_unlock(); /* only allocate BPF data if there are programs attached */ - if (!prog_list) + if (!need_to_allocate) return 0; return hid_bpf_allocate_event_data(hdev); @@ -623,12 +651,15 @@ void hid_bpf_destroy_device(struct hid_device *hdev) hdev->bpf.destroyed = true; __hid_bpf_destroy_device(hdev); + __hid_bpf_ops_destroy_device(hdev); } EXPORT_SYMBOL_GPL(hid_bpf_destroy_device); void hid_bpf_device_init(struct hid_device *hdev) { spin_lock_init(&hdev->bpf.progs_lock); + INIT_LIST_HEAD(&hdev->bpf.prog_list); + mutex_init(&hdev->bpf.prog_list_lock); } EXPORT_SYMBOL_GPL(hid_bpf_device_init); @@ -662,6 +693,13 @@ static int __init hid_bpf_init(void) return 0; } + /* register struct_ops kfuncs after we are sure we can load our preloaded bpf program */ + 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; + } + /* register syscalls after we are sure we can load our preloaded bpf program */ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set); if (err) { diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h index fbe0639d09f2..e52c43d81650 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.h +++ b/drivers/hid/bpf/hid_bpf_dispatch.h @@ -10,12 +10,16 @@ struct hid_bpf_ctx_kern { u8 *data; }; +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); int hid_bpf_preload_skel(void); void hid_bpf_free_links_and_skel(void); int hid_bpf_get_prog_attach_type(struct bpf_prog *prog); int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd, struct bpf_prog *prog, __u32 flags); void __hid_bpf_destroy_device(struct hid_device *hdev); +void __hid_bpf_ops_destroy_device(struct hid_device *hdev); int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, struct hid_bpf_ctx_kern *ctx_kern); int hid_bpf_reconnect(struct hid_device *hdev); diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c index aa8e1c79cdf5..8a54ba447718 100644 --- a/drivers/hid/bpf/hid_bpf_jmp_table.c +++ b/drivers/hid/bpf/hid_bpf_jmp_table.c @@ -81,6 +81,9 @@ static int hid_bpf_program_count(struct hid_device *hdev, if (type >= HID_BPF_PROG_TYPE_MAX) return -EINVAL; + if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && hdev->bpf.rdesc_ops) + n += 1; + FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; 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 000000000000..dde547e734ed --- /dev/null +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * HID-BPF support for Linux + * + * Copyright (c) 2024 Benjamin Tissoires + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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): + break; + default: + if (prog->sleepable) + return -EINVAL; + } + + return 0; +} + +static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log, + const struct bpf_reg_state *reg, + int off, int size) +{ + const struct btf_type *state; + const struct btf_type *t; + s32 type_id; + + type_id = btf_find_by_name_kind(reg->btf, "hid_bpf_ctx", + BTF_KIND_STRUCT); + if (type_id < 0) + return -EINVAL; + + t = btf_type_by_id(reg->btf, reg->btf_id); + state = btf_type_by_id(reg->btf, type_id); + if (t != state) { + bpf_log(log, "only access to hid_bpf_ctx is supported\n"); + return -EACCES; + } + + /* out-of-bound access in hid_bpf_ctx */ + if (off + size > sizeof(struct hid_bpf_ctx)) { + bpf_log(log, "write access at off %d with size %d\n", off, size); + return -EACCES; + } + + if (off < offsetof(struct hid_bpf_ctx, retval)) { + bpf_log(log, + "write access at off %d with size %d on read-only part of hid_bpf_ctx\n", + off, size); + return -EACCES; + } + + return NOT_INIT; +} + +static const struct bpf_verifier_ops hid_bpf_verifier_ops = { + .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 hid_bpf_ops *ops = kdata; + struct hid_device *hdev; + int count, err = 0; + + 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); + +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 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); + + list_del_rcu(&ops->list); + + 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) +{ + return 0; +} + +static int __hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx) +{ + 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, +}; + +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; + + rcu_read_lock(); + list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) { + hid_put_device(hdev); + e->hdev = NULL; + } + rcu_read_unlock(); +} + +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/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index a66103618e6e..c4f4ce10b7dd 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -65,11 +65,12 @@ struct hid_bpf_ctx { * @HID_BPF_FLAG_INSERT_HEAD: insert the given program before any other program * currently attached to the device. This doesn't * guarantee that this program will always be first - * @HID_BPF_FLAG_MAX: sentinel value, not to be used by the callers */ enum hid_bpf_attach_flags { HID_BPF_FLAG_NONE = 0, HID_BPF_FLAG_INSERT_HEAD = _BITUL(0), + + /* private: internal use only */ HID_BPF_FLAG_MAX, }; @@ -112,6 +113,60 @@ struct hid_ops { extern struct hid_ops *hid_ops; +/** + * struct hid_bpf_ops - A BPF struct_ops of callbacks allowing to attach HID-BPF + * programs to a HID device + * @hid_id: the HID uniq ID to attach to. This is writeable before ``load()``, and + * cannot be changed after + * @flags: flags used while attaching the struct_ops to the device. Currently only + * available value is %0 or ``BPF_F_BEFORE``. + * Writeable only before ``load()`` + */ +struct hid_bpf_ops { + /* hid_id needs to stay first so we can easily change it + * from userspace. + */ + int hid_id; + u32 flags; + + /* private: do not show up in the docs */ + struct list_head list; + + /* public: rest should show up in the docs */ + + /** + * @hid_device_event: called whenever an event is coming in from the device + * + * It has the following arguments: + * + * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * + * Return: %0 on success and keep processing; a positive + * value to change the incoming size buffer; a negative + * error code to interrupt the processing of this event + * + * Context: Interrupt context. + */ + int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type); + + /** + * @hid_rdesc_fixup: called when the probe function parses the report descriptor + * of the HID device + * + * It has the following arguments: + * + * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * + * Return: %0 on success and keep processing; a positive + * value to change the incoming size buffer; a negative + * error code to interrupt the processing of this device + */ + int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); + + /* private: do not show up in the docs */ + struct hid_device *hdev; +}; + struct hid_bpf_prog_list { u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV]; u8 prog_cnt; @@ -129,6 +184,10 @@ struct hid_bpf { bool destroyed; /* prevents the assignment of any progs */ spinlock_t progs_lock; /* protects RCU update of progs */ + + struct hid_bpf_ops *rdesc_ops; + struct list_head prog_list; + struct mutex prog_list_lock; /* protects prog_list update */ }; /* specific HID-BPF link when a program is attached to a device */ From d7696738d66b4f1379fe77eef61cd1047d7f0773 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:16 +0200 Subject: [PATCH 15/60] selftests/hid: convert the hid_bpf selftests with struct_ops We drop the need for the attach() bpf syscall, but we need to set up the hid_id field before calling __load(). The .bpf.c part is mechanical: we create one struct_ops per HID-BPF program, as all the tests are for one program at a time. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-4-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 59 +++++++------- tools/testing/selftests/hid/progs/hid.c | 76 +++++++++++++------ .../selftests/hid/progs/hid_bpf_helpers.h | 19 +---- 3 files changed, 89 insertions(+), 65 deletions(-) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index f825623e3edc..967dfe6b58cb 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -460,7 +460,7 @@ FIXTURE(hid_bpf) { int hid_id; pthread_t tid; struct hid *skel; - int hid_links[3]; /* max number of programs loaded in a single test */ + struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */ }; static void detach_bpf(FIXTURE_DATA(hid_bpf) * self) { @@ -472,7 +472,7 @@ static void detach_bpf(FIXTURE_DATA(hid_bpf) * self) for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) { if (self->hid_links[i]) - close(self->hid_links[i]); + bpf_link__destroy(self->hid_links[i]); } hid__destroy(self->skel); @@ -527,14 +527,7 @@ static void load_programs(const struct test_program programs[], FIXTURE_DATA(hid_bpf) * self, const FIXTURE_VARIANT(hid_bpf) * variant) { - int attach_fd, err = -EINVAL; - struct attach_prog_args args = { - .retval = -1, - }; - DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr, - .ctx_in = &args, - .ctx_size_in = sizeof(args), - ); + int err = -EINVAL; ASSERT_LE(progs_count, ARRAY_SIZE(self->hid_links)) TH_LOG("too many programs are to be loaded"); @@ -545,35 +538,41 @@ static void load_programs(const struct test_program programs[], for (int i = 0; i < progs_count; i++) { struct bpf_program *prog; + struct bpf_map *map; + int *ops_hid_id; prog = bpf_object__find_program_by_name(*self->skel->skeleton->obj, programs[i].name); ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name); bpf_program__set_autoload(prog, true); + + map = bpf_object__find_map_by_name(*self->skel->skeleton->obj, + programs[i].name + 4); + ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", + programs[i].name + 4); + + /* hid_id is the first field of struct hid_bpf_ops */ + ops_hid_id = bpf_map__initial_value(map, NULL); + ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data"); + + *ops_hid_id = self->hid_id; } err = hid__load(self->skel); ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err); - attach_fd = bpf_program__fd(self->skel->progs.attach_prog); - ASSERT_GE(attach_fd, 0) TH_LOG("locate attach_prog: %d", attach_fd); - for (int i = 0; i < progs_count; i++) { - struct bpf_program *prog; + struct bpf_map *map; - prog = bpf_object__find_program_by_name(*self->skel->skeleton->obj, - programs[i].name); - ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name); + map = bpf_object__find_map_by_name(*self->skel->skeleton->obj, + programs[i].name + 4); + ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", + programs[i].name + 4); - args.prog_fd = bpf_program__fd(prog); - args.hid = self->hid_id; - args.insert_head = programs[i].insert_head; - err = bpf_prog_test_run_opts(attach_fd, &tattr); - ASSERT_GE(args.retval, 0) - TH_LOG("attach_hid(%s): %d", programs[i].name, args.retval); - - self->hid_links[i] = args.retval; + self->hid_links[i] = bpf_map__attach_struct_ops(map); + ASSERT_OK_PTR(self->hid_links[i]) TH_LOG("failed to attach struct ops '%s'", + programs[i].name + 4); } self->hidraw_fd = open_hidraw(self->dev_id); @@ -648,13 +647,17 @@ TEST_F(hid_bpf, test_attach_detach) { .name = "hid_first_event" }, { .name = "hid_second_event" }, }; + struct bpf_link *link; __u8 buf[10] = {0}; - int err, link; + int err, link_fd; LOAD_PROGRAMS(progs); link = self->hid_links[0]; - ASSERT_GT(link, 0) TH_LOG("HID-BPF link not created"); + ASSERT_OK_PTR(link) TH_LOG("HID-BPF link not created"); + + link_fd = bpf_link__fd(link); + ASSERT_GE(link_fd, 0) TH_LOG("HID-BPF link FD not valid"); /* inject one event */ buf[0] = 1; @@ -673,7 +676,7 @@ TEST_F(hid_bpf, test_attach_detach) /* pin the first program and immediately unpin it */ #define PIN_PATH "/sys/fs/bpf/hid_first_event" - err = bpf_obj_pin(link, PIN_PATH); + err = bpf_obj_pin(link_fd, PIN_PATH); ASSERT_OK(err) TH_LOG("error while calling bpf_obj_pin"); remove(PIN_PATH); #undef PIN_PATH diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index f67d35def142..614f1aa32649 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -14,8 +14,8 @@ struct attach_prog_args { __u64 callback_check = 52; __u64 callback2_check = 52; -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx) +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); @@ -29,8 +29,14 @@ int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx) return hid_ctx->size; } -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx) +SEC(".struct_ops.link") +struct hid_bpf_ops first_event = { + .hid_device_event = (void *)hid_first_event, + .hid_id = 2, +}; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); @@ -42,8 +48,13 @@ int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx) return hid_ctx->size; } -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx) +SEC(".struct_ops.link") +struct hid_bpf_ops second_event = { + .hid_device_event = (void *)hid_second_event, +}; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); @@ -55,15 +66,10 @@ int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx) return 9; } -SEC("syscall") -int attach_prog(struct attach_prog_args *ctx) -{ - ctx->retval = hid_bpf_attach_prog(ctx->hid, - ctx->prog_fd, - ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD : - HID_BPF_FLAG_NONE); - return 0; -} +SEC(".struct_ops.link") +struct hid_bpf_ops change_report_id = { + .hid_device_event = (void *)hid_change_report_id, +}; struct hid_hw_request_syscall_args { /* data needs to come at offset 0 so we can use it in calls */ @@ -181,7 +187,12 @@ static const __u8 rdesc[] = { 0xc0, /* END_COLLECTION */ }; -SEC("?fmod_ret/hid_bpf_rdesc_fixup") +/* + * the following program is marked as sleepable (struct_ops.s). + * This is not strictly mandatory but is a nice test for + * sleepable struct_ops + */ +SEC("?struct_ops.s/hid_rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */); @@ -200,8 +211,13 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx) return sizeof(rdesc) + 73; } -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx) +SEC(".struct_ops.link") +struct hid_bpf_ops rdesc_fixup = { + .hid_rdesc_fixup = (void *)hid_rdesc_fixup, +}; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); @@ -217,8 +233,14 @@ int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx) return 0; } -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx) +SEC(".struct_ops.link") +struct hid_bpf_ops test_insert1 = { + .hid_device_event = (void *)hid_test_insert1, + .flags = BPF_F_BEFORE, +}; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); @@ -234,8 +256,13 @@ int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx) return 0; } -SEC("?fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx) +SEC(".struct_ops.link") +struct hid_bpf_ops test_insert2 = { + .hid_device_event = (void *)hid_test_insert2, +}; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); @@ -250,3 +277,8 @@ int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx) return 0; } + +SEC(".struct_ops.link") +struct hid_bpf_ops test_insert3 = { + .hid_device_event = (void *)hid_test_insert3, +}; diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h index 9cd56821d0f1..e02e24e3eab3 100644 --- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h @@ -20,9 +20,6 @@ #define HID_REQ_SET_REPORT HID_REQ_SET_REPORT___not_used #define HID_REQ_SET_IDLE HID_REQ_SET_IDLE___not_used #define HID_REQ_SET_PROTOCOL HID_REQ_SET_PROTOCOL___not_used -#define HID_BPF_FLAG_NONE HID_BPF_FLAG_NONE___not_used -#define HID_BPF_FLAG_INSERT_HEAD HID_BPF_FLAG_INSERT_HEAD___not_used -#define HID_BPF_FLAG_MAX HID_BPF_FLAG_MAX___not_used #include "vmlinux.h" @@ -40,9 +37,6 @@ #undef HID_REQ_SET_REPORT #undef HID_REQ_SET_IDLE #undef HID_REQ_SET_PROTOCOL -#undef HID_BPF_FLAG_NONE -#undef HID_BPF_FLAG_INSERT_HEAD -#undef HID_BPF_FLAG_MAX #include #include @@ -57,10 +51,8 @@ enum hid_report_type { }; struct hid_bpf_ctx { - __u32 index; - const struct hid_device *hid; + struct hid_device *hid; __u32 allocated_size; - enum hid_report_type report_type; union { __s32 retval; __s32 size; @@ -76,17 +68,14 @@ enum hid_class_request { HID_REQ_SET_PROTOCOL = 0x0B, }; -enum hid_bpf_attach_flags { - HID_BPF_FLAG_NONE = 0, - HID_BPF_FLAG_INSERT_HEAD = _BITUL(0), - HID_BPF_FLAG_MAX, -}; +#ifndef BPF_F_BEFORE +#define BPF_F_BEFORE (1U << 3) +#endif /* following are kfuncs exported by HID for HID-BPF */ extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; -extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __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, From e342d6f6f7d82b48c4540b947d8032a3b7b3e6f8 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:17 +0200 Subject: [PATCH 16/60] HID: samples: convert the 2 HID-BPF samples into struct_ops This is mostly mechanical: attach_prog is dropped, and the SEC are converted into struct_ops. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-5-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- samples/hid/Makefile | 5 ++- samples/hid/hid_bpf_attach.bpf.c | 18 ---------- samples/hid/hid_bpf_attach.h | 14 -------- samples/hid/hid_mouse.bpf.c | 26 ++++++++++++--- samples/hid/hid_mouse.c | 39 +++++++--------------- samples/hid/hid_surface_dial.bpf.c | 10 ++++-- samples/hid/hid_surface_dial.c | 53 +++++++++--------------------- 7 files changed, 57 insertions(+), 108 deletions(-) delete mode 100644 samples/hid/hid_bpf_attach.bpf.c delete mode 100644 samples/hid/hid_bpf_attach.h diff --git a/samples/hid/Makefile b/samples/hid/Makefile index c128ccd49974..8ea59e9631a3 100644 --- a/samples/hid/Makefile +++ b/samples/hid/Makefile @@ -16,7 +16,6 @@ LIBBPF_DESTDIR = $(LIBBPF_OUTPUT) LIBBPF_INCLUDE = $(LIBBPF_DESTDIR)/include LIBBPF = $(LIBBPF_OUTPUT)/libbpf.a -EXTRA_HEADERS := hid_bpf_attach.h EXTRA_BPF_HEADERS := hid_bpf_helpers.h hid_mouse-objs := hid_mouse.o @@ -207,8 +206,8 @@ $(obj)/%.bpf.o: $(src)/%.bpf.c $(EXTRA_BPF_HEADERS_SRC) $(obj)/vmlinux.h LINKED_SKELS := hid_mouse.skel.h hid_surface_dial.skel.h clean-files += $(LINKED_SKELS) -hid_mouse.skel.h-deps := hid_mouse.bpf.o hid_bpf_attach.bpf.o -hid_surface_dial.skel.h-deps := hid_surface_dial.bpf.o hid_bpf_attach.bpf.o +hid_mouse.skel.h-deps := hid_mouse.bpf.o +hid_surface_dial.skel.h-deps := hid_surface_dial.bpf.o LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.bpf.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps))) diff --git a/samples/hid/hid_bpf_attach.bpf.c b/samples/hid/hid_bpf_attach.bpf.c deleted file mode 100644 index d4dce4ea7c6e..000000000000 --- a/samples/hid/hid_bpf_attach.bpf.c +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2022 Benjamin Tissoires - */ - -#include "vmlinux.h" -#include -#include -#include "hid_bpf_attach.h" -#include "hid_bpf_helpers.h" - -SEC("syscall") -int attach_prog(struct attach_prog_args *ctx) -{ - ctx->retval = hid_bpf_attach_prog(ctx->hid, - ctx->prog_fd, - 0); - return 0; -} diff --git a/samples/hid/hid_bpf_attach.h b/samples/hid/hid_bpf_attach.h deleted file mode 100644 index 35bb28b49264..000000000000 --- a/samples/hid/hid_bpf_attach.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2022 Benjamin Tissoires - */ - -#ifndef __HID_BPF_ATTACH_H -#define __HID_BPF_ATTACH_H - -struct attach_prog_args { - int prog_fd; - unsigned int hid; - int retval; -}; - -#endif /* __HID_BPF_ATTACH_H */ diff --git a/samples/hid/hid_mouse.bpf.c b/samples/hid/hid_mouse.bpf.c index 7c8b453ccb16..bd901fa855c9 100644 --- a/samples/hid/hid_mouse.bpf.c +++ b/samples/hid/hid_mouse.bpf.c @@ -5,8 +5,7 @@ #include #include "hid_bpf_helpers.h" -SEC("fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_y_event, struct hid_bpf_ctx *hctx) +static int hid_y_event(struct hid_bpf_ctx *hctx) { s16 y; __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */); @@ -51,8 +50,7 @@ int BPF_PROG(hid_y_event, struct hid_bpf_ctx *hctx) return 0; } -SEC("fmod_ret/hid_bpf_device_event") -int BPF_PROG(hid_x_event, struct hid_bpf_ctx *hctx) +static int hid_x_event(struct hid_bpf_ctx *hctx) { s16 x; __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */); @@ -69,7 +67,19 @@ int BPF_PROG(hid_x_event, struct hid_bpf_ctx *hctx) return 0; } -SEC("fmod_ret/hid_bpf_rdesc_fixup") +SEC("struct_ops/device_event") +int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx, enum hid_report_type type) +{ + int ret = hid_y_event(hctx); + + if (ret) + return ret; + + return hid_x_event(hctx); +} + + +SEC("struct_ops/rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); @@ -109,4 +119,10 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) return 0; } +SEC(".struct_ops.link") +struct hid_bpf_ops mouse_invert = { + .rdesc_fixup = (void *)hid_rdesc_fixup, + .device_event = (void *)hid_event, +}; + char _license[] SEC("license") = "GPL"; diff --git a/samples/hid/hid_mouse.c b/samples/hid/hid_mouse.c index 018f1185f203..4b80d4e4c154 100644 --- a/samples/hid/hid_mouse.c +++ b/samples/hid/hid_mouse.c @@ -29,7 +29,6 @@ #include #include "hid_mouse.skel.h" -#include "hid_bpf_attach.h" static bool running = true; @@ -76,18 +75,11 @@ static int get_hid_id(const char *path) int main(int argc, char **argv) { struct hid_mouse *skel; - struct bpf_program *prog; + struct bpf_link *link; int err; const char *optstr = ""; const char *sysfs_path; - int opt, hid_id, attach_fd; - struct attach_prog_args args = { - .retval = -1, - }; - DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr, - .ctx_in = &args, - .ctx_size_in = sizeof(args), - ); + int opt, hid_id; while ((opt = getopt(argc, argv, optstr)) != -1) { switch (opt) { @@ -108,7 +100,7 @@ int main(int argc, char **argv) return 1; } - skel = hid_mouse__open_and_load(); + skel = hid_mouse__open(); if (!skel) { fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__); return -1; @@ -120,27 +112,18 @@ int main(int argc, char **argv) fprintf(stderr, "can not open HID device: %m\n"); return 1; } - args.hid = hid_id; + skel->struct_ops.mouse_invert->hid_id = hid_id; - attach_fd = bpf_program__fd(skel->progs.attach_prog); - if (attach_fd < 0) { - fprintf(stderr, "can't locate attach prog: %m\n"); + err = hid_mouse__load(skel); + if (err < 0) { + fprintf(stderr, "can not load HID-BPF program: %m\n"); return 1; } - bpf_object__for_each_program(prog, *skel->skeleton->obj) { - /* ignore syscalls */ - if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING) - continue; - - args.retval = -1; - args.prog_fd = bpf_program__fd(prog); - err = bpf_prog_test_run_opts(attach_fd, &tattr); - if (err) { - fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n", - hid_id, err); - return 1; - } + link = bpf_map__attach_struct_ops(skel->maps.mouse_invert); + if (!link) { + fprintf(stderr, "can not attach HID-BPF program: %m\n"); + return 1; } signal(SIGINT, int_exit); diff --git a/samples/hid/hid_surface_dial.bpf.c b/samples/hid/hid_surface_dial.bpf.c index 1f80478c0918..d8d0fb07391f 100644 --- a/samples/hid/hid_surface_dial.bpf.c +++ b/samples/hid/hid_surface_dial.bpf.c @@ -10,7 +10,7 @@ #define HID_UP_BUTTON 0x0009 #define HID_GD_WHEEL 0x0038 -SEC("fmod_ret/hid_bpf_device_event") +SEC("struct_ops/device_event") int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */); @@ -101,7 +101,7 @@ int set_haptic(struct haptic_syscall_args *args) } /* Convert REL_DIAL into REL_WHEEL */ -SEC("fmod_ret/hid_bpf_rdesc_fixup") +SEC("struct_ops/rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); @@ -130,5 +130,11 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) return 0; } +SEC(".struct_ops.link") +struct hid_bpf_ops surface_dial = { + .rdesc_fixup = (void *)hid_rdesc_fixup, + .device_event = (void *)hid_event, +}; + char _license[] SEC("license") = "GPL"; u32 _version SEC("version") = 1; diff --git a/samples/hid/hid_surface_dial.c b/samples/hid/hid_surface_dial.c index 4bc97373a708..9dd363845a85 100644 --- a/samples/hid/hid_surface_dial.c +++ b/samples/hid/hid_surface_dial.c @@ -31,7 +31,6 @@ #include #include "hid_surface_dial.skel.h" -#include "hid_bpf_attach.h" static bool running = true; @@ -86,34 +85,6 @@ static int get_hid_id(const char *path) return (int)strtol(str_id, NULL, 16); } -static int attach_prog(struct hid_surface_dial *skel, struct bpf_program *prog, int hid_id) -{ - struct attach_prog_args args = { - .hid = hid_id, - .retval = -1, - }; - int attach_fd, err; - DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr, - .ctx_in = &args, - .ctx_size_in = sizeof(args), - ); - - attach_fd = bpf_program__fd(skel->progs.attach_prog); - if (attach_fd < 0) { - fprintf(stderr, "can't locate attach prog: %m\n"); - return 1; - } - - args.prog_fd = bpf_program__fd(prog); - err = bpf_prog_test_run_opts(attach_fd, &tattr); - if (err) { - fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n", - hid_id, err); - return 1; - } - return 0; -} - static int set_haptic(struct hid_surface_dial *skel, int hid_id) { struct haptic_syscall_args args = { @@ -144,10 +115,10 @@ static int set_haptic(struct hid_surface_dial *skel, int hid_id) int main(int argc, char **argv) { struct hid_surface_dial *skel; - struct bpf_program *prog; const char *optstr = "r:"; + struct bpf_link *link; const char *sysfs_path; - int opt, hid_id, resolution = 72; + int err, opt, hid_id, resolution = 72; while ((opt = getopt(argc, argv, optstr)) != -1) { switch (opt) { @@ -189,7 +160,7 @@ int main(int argc, char **argv) return 1; } - skel = hid_surface_dial__open_and_load(); + skel = hid_surface_dial__open(); if (!skel) { fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__); return -1; @@ -201,15 +172,21 @@ int main(int argc, char **argv) return 1; } + skel->struct_ops.surface_dial->hid_id = hid_id; + + err = hid_surface_dial__load(skel); + if (err < 0) { + fprintf(stderr, "can not load HID-BPF program: %m\n"); + return 1; + } + skel->data->resolution = resolution; skel->data->physical = (int)(resolution / 72); - bpf_object__for_each_program(prog, *skel->skeleton->obj) { - /* ignore syscalls */ - if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING) - continue; - - attach_prog(skel, prog, hid_id); + link = bpf_map__attach_struct_ops(skel->maps.surface_dial); + if (!link) { + fprintf(stderr, "can not attach HID-BPF program: %m\n"); + return 1; } signal(SIGINT, int_exit); From df67602fb8d5a02e40f37efcf4b5cb958c8ca880 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:18 +0200 Subject: [PATCH 17/60] HID: bpf: add defines for HID-BPF SEC in in-tree bpf fixes We are going to switch over struct_ops, so instead of having to manually replace all fields one by one, let's have a common place to change it. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-6-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c | 4 ++-- drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c | 2 +- drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c | 4 ++-- drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c | 2 +- drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c | 2 +- drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c | 2 +- drivers/hid/bpf/progs/XPPen__Artist24.bpf.c | 4 ++-- drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c | 6 +++--- drivers/hid/bpf/progs/hid_bpf.h | 3 +++ 9 files changed, 16 insertions(+), 13 deletions(-) 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 index dc26a7677d36..2c2c1637ade8 100644 --- a/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c +++ b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c @@ -133,7 +133,7 @@ HID_BPF_CONFIG( * integer. We thus divide it by 30 to match what other joysticks are * doing */ -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); @@ -152,7 +152,7 @@ int BPF_PROG(hid_fix_rdesc_raptor_mach_2, struct hid_bpf_ctx *hctx) * divide it by 30. * Byte 34 is always null, so it is ignored. */ -SEC("fmod_ret/hid_bpf_device_event") +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 */); diff --git a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c index 3d14bbb6f276..17fc55f6f02c 100644 --- a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c +++ b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c @@ -30,7 +30,7 @@ HID_BPF_CONFIG( * pointer. */ -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); diff --git a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c index ff759f2276f9..24b8a5aa05f3 100644 --- a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c +++ b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c @@ -191,7 +191,7 @@ static const __u8 fixed_rdesc[] = { 0xc0, // End Collection 327 }; -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); @@ -215,7 +215,7 @@ int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx) * - if there was this out-of-proximity event, we are entering * eraser mode, and we will until the next out-of-proximity. */ -SEC("fmod_ret/hid_bpf_device_event") +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 */); diff --git a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c index 225cbefdbf0e..bee37872ee8c 100644 --- a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c +++ b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c @@ -21,7 +21,7 @@ HID_BPF_CONFIG( * We just fix the report descriptor to enable those missing 7 buttons. */ -SEC("fmod_ret/hid_bpf_rdesc_fixup") +SEC(HID_BPF_RDESC_FIXUP) int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) { const u8 offsets[] = {84, 112, 140}; diff --git a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c index c04abecab8ee..f9ad33f4a373 100644 --- a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c +++ b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c @@ -93,7 +93,7 @@ _Static_assert(sizeof(rdesc_assign_selection) == sizeof(fixed_rdesc_assign_selec _Static_assert(sizeof(rdesc_assign_selection) + OFFSET_ASSIGN_SELECTION < ORIGINAL_RDESC_SIZE, "Rdesc at given offset is too big"); -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); diff --git a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c index dc05aa48faa7..39d77c5e9172 100644 --- a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c +++ b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c @@ -101,7 +101,7 @@ static inline __u8 *get_u8(__u8 *data, unsigned int offset) return (__u8 *)get_bits(data, offset); } -SEC("fmod_ret/hid_bpf_device_event") +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 */); diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c index e1be6a12bb75..c938808bd589 100644 --- a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c @@ -91,7 +91,7 @@ static const __u8 fixed_rdesc[] = { #define U16(index) (data[index] | (data[index + 1] << 8)) -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); @@ -152,7 +152,7 @@ static __u8 prev_state = 0; * E: TipSwitch InRange * */ -SEC("fmod_ret/hid_bpf_device_event") +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 */); diff --git a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c index 65ef10036126..77ef8b95d52e 100644 --- a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c @@ -82,7 +82,7 @@ static const __u8 fixed_rdesc[] = { 0xc0, // End Collection 112 }; -SEC("fmod_ret/hid_bpf_rdesc_fixup") +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 */); @@ -105,7 +105,7 @@ int BPF_PROG(hid_fix_rdesc_xppen_artistpro16gen2, struct hid_bpf_ctx *hctx) return sizeof(fixed_rdesc); } -SEC("fmod_ret/hid_bpf_device_event") +SEC(HID_BPF_DEVICE_EVENT) int BPF_PROG(xppen_16_fix_eraser, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); @@ -207,7 +207,7 @@ static void compensate_coordinates_by_tilt(__u8 *data, const __u8 idx, data[idx+1] = coords >> 8; } -SEC("fmod_ret/hid_bpf_device_event") +SEC(HID_BPF_DEVICE_EVENT) int BPF_PROG(xppen_16_fix_angle_offset, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); diff --git a/drivers/hid/bpf/progs/hid_bpf.h b/drivers/hid/bpf/progs/hid_bpf.h index 7ee371cac2e1..1970faf84310 100644 --- a/drivers/hid/bpf/progs/hid_bpf.h +++ b/drivers/hid/bpf/progs/hid_bpf.h @@ -5,6 +5,9 @@ #ifndef ____HID_BPF__H #define ____HID_BPF__H +#define HID_BPF_DEVICE_EVENT "fmod_ret/hid_bpf_device_event" +#define HID_BPF_RDESC_FIXUP "fmod_ret/hid_bpf_rdesc_fixup" + struct hid_bpf_probe_args { unsigned int hid; unsigned int rdesc_size; From 50fe0fc6e206c9b85a0a6cc183ee5513d70179d1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:19 +0200 Subject: [PATCH 18/60] HID: bpf: convert in-tree fixes into struct_ops Very mechanical: - Change HID_BPF_DEVICE_EVENT and HID_BPF_RDESC_FIXUP #defines - add a matching SEC(".struct_ops.link") - in ArtistPro16Gen2 make the 2 functions static and have a new one calling them Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-7-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- .../hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c | 5 +++++ .../hid/bpf/progs/HP__Elite-Presenter.bpf.c | 4 ++++ .../hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c | 5 +++++ .../bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c | 4 ++++ .../bpf/progs/Microsoft__XBox-Elite-2.bpf.c | 4 ++++ drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c | 4 ++++ drivers/hid/bpf/progs/XPPen__Artist24.bpf.c | 5 +++++ .../bpf/progs/XPPen__ArtistPro16Gen2.bpf.c | 22 +++++++++++++++---- drivers/hid/bpf/progs/hid_bpf.h | 6 +++-- 9 files changed, 53 insertions(+), 6 deletions(-) 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 index 2c2c1637ade8..caec91391d32 100644 --- a/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c +++ b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c @@ -168,6 +168,11 @@ int BPF_PROG(raptor_mach_2_fix_hat_switch, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c index 17fc55f6f02c..c2413fa80543 100644 --- a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c +++ b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c @@ -45,6 +45,10 @@ int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c index 24b8a5aa05f3..a4a4f324aedd 100644 --- a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c +++ b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c @@ -255,6 +255,11 @@ int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c index bee37872ee8c..82f1950445dd 100644 --- a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c +++ b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c @@ -45,6 +45,10 @@ int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c index f9ad33f4a373..70b16edfb59a 100644 --- a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c +++ b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c @@ -114,6 +114,10 @@ int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c index 39d77c5e9172..2da680bc4e11 100644 --- a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c +++ b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c @@ -139,6 +139,10 @@ int BPF_PROG(artpen_pressure_interpolate, struct hid_bpf_ctx *hctx) return 0; } +HID_BPF_OPS(wacom_artpen) = { + .hid_device_event = (void *)artpen_pressure_interpolate, +}; + SEC("syscall") int probe(struct hid_bpf_probe_args *ctx) { diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c index c938808bd589..bc0b85c38445 100644 --- a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c @@ -209,6 +209,11 @@ int BPF_PROG(xppen_24_fix_eraser, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c index 77ef8b95d52e..a669525691aa 100644 --- a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c @@ -105,8 +105,7 @@ int BPF_PROG(hid_fix_rdesc_xppen_artistpro16gen2, struct hid_bpf_ctx *hctx) return sizeof(fixed_rdesc); } -SEC(HID_BPF_DEVICE_EVENT) -int BPF_PROG(xppen_16_fix_eraser, struct hid_bpf_ctx *hctx) +static int xppen_16_fix_eraser(struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); @@ -207,8 +206,7 @@ static void compensate_coordinates_by_tilt(__u8 *data, const __u8 idx, data[idx+1] = coords >> 8; } -SEC(HID_BPF_DEVICE_EVENT) -int BPF_PROG(xppen_16_fix_angle_offset, struct hid_bpf_ctx *hctx) +static int xppen_16_fix_angle_offset(struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); @@ -254,6 +252,22 @@ int BPF_PROG(xppen_16_fix_angle_offset, struct hid_bpf_ctx *hctx) 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) { diff --git a/drivers/hid/bpf/progs/hid_bpf.h b/drivers/hid/bpf/progs/hid_bpf.h index 1970faf84310..8c1cd9e25bc3 100644 --- a/drivers/hid/bpf/progs/hid_bpf.h +++ b/drivers/hid/bpf/progs/hid_bpf.h @@ -5,8 +5,10 @@ #ifndef ____HID_BPF__H #define ____HID_BPF__H -#define HID_BPF_DEVICE_EVENT "fmod_ret/hid_bpf_device_event" -#define HID_BPF_RDESC_FIXUP "fmod_ret/hid_bpf_rdesc_fixup" +#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 struct hid_bpf_probe_args { unsigned int hid; From 4a86220e046da009bef0948e9f51d1d26d68f93c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:20 +0200 Subject: [PATCH 19/60] HID: bpf: remove tracing HID-BPF capability We can now rely on struct_ops as we cleared the users in-tree. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-8-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/Makefile | 2 +- drivers/hid/bpf/entrypoints/Makefile | 93 --- drivers/hid/bpf/entrypoints/README | 4 - drivers/hid/bpf/entrypoints/entrypoints.bpf.c | 25 - .../hid/bpf/entrypoints/entrypoints.lskel.h | 248 -------- drivers/hid/bpf/hid_bpf_dispatch.c | 193 +----- drivers/hid/bpf/hid_bpf_dispatch.h | 8 - drivers/hid/bpf/hid_bpf_jmp_table.c | 568 ------------------ include/linux/hid_bpf.h | 54 +- 9 files changed, 8 insertions(+), 1187 deletions(-) delete mode 100644 drivers/hid/bpf/entrypoints/Makefile delete mode 100644 drivers/hid/bpf/entrypoints/README delete mode 100644 drivers/hid/bpf/entrypoints/entrypoints.bpf.c delete mode 100644 drivers/hid/bpf/entrypoints/entrypoints.lskel.h delete mode 100644 drivers/hid/bpf/hid_bpf_jmp_table.c diff --git a/drivers/hid/bpf/Makefile b/drivers/hid/bpf/Makefile index 1cb3f31e9335..d1f2b81788ca 100644 --- a/drivers/hid/bpf/Makefile +++ b/drivers/hid/bpf/Makefile @@ -8,4 +8,4 @@ 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_jmp_table.o hid_bpf_struct_ops.o +hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_struct_ops.o diff --git a/drivers/hid/bpf/entrypoints/Makefile b/drivers/hid/bpf/entrypoints/Makefile deleted file mode 100644 index 43b99b5575cf..000000000000 --- a/drivers/hid/bpf/entrypoints/Makefile +++ /dev/null @@ -1,93 +0,0 @@ -# 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 - -all: entrypoints.lskel.h - -clean: - $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) entrypoints - -entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL) - $(call msg,GEN-SKEL,$@) - $(Q)$(BPFTOOL) gen skeleton -L $< > $@ - - -$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT) - $(call msg,BPF,$@) - $(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \ - -c $(filter %.c,$^) -o $@ && \ - $(LLVM_STRIP) -g $@ - -$(OUTPUT)/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/entrypoints/README b/drivers/hid/bpf/entrypoints/README deleted file mode 100644 index 147e0d41509f..000000000000 --- a/drivers/hid/bpf/entrypoints/README +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: -If you change "entrypoints.bpf.c" do "make -j" in this directory to rebuild "entrypoints.skel.h". -Make sure to have clang 10 installed. -See Documentation/bpf/bpf_devel_QA.rst diff --git a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c deleted file mode 100644 index c22921125a1a..000000000000 --- a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2022 Benjamin Tissoires */ - -#include ".output/vmlinux.h" -#include -#include - -#define HID_BPF_MAX_PROGS 1024 - -struct { - __uint(type, BPF_MAP_TYPE_PROG_ARRAY); - __uint(max_entries, HID_BPF_MAX_PROGS); - __uint(key_size, sizeof(__u32)); - __uint(value_size, sizeof(__u32)); -} hid_jmp_table SEC(".maps"); - -SEC("fmod_ret/__hid_bpf_tail_call") -int BPF_PROG(hid_tail_call, struct hid_bpf_ctx *hctx) -{ - bpf_tail_call(ctx, &hid_jmp_table, hctx->index); - - return 0; -} - -char LICENSE[] SEC("license") = "GPL"; diff --git a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h deleted file mode 100644 index 35618051598c..000000000000 --- a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h +++ /dev/null @@ -1,248 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */ -#ifndef __ENTRYPOINTS_BPF_SKEL_H__ -#define __ENTRYPOINTS_BPF_SKEL_H__ - -#include - -struct entrypoints_bpf { - struct bpf_loader_ctx ctx; - struct { - struct bpf_map_desc hid_jmp_table; - } maps; - struct { - struct bpf_prog_desc hid_tail_call; - } progs; - struct { - int hid_tail_call_fd; - } links; -}; - -static inline int -entrypoints_bpf__hid_tail_call__attach(struct entrypoints_bpf *skel) -{ - int prog_fd = skel->progs.hid_tail_call.prog_fd; - int fd = skel_raw_tracepoint_open(NULL, prog_fd); - - if (fd > 0) - skel->links.hid_tail_call_fd = fd; - return fd; -} - -static inline int -entrypoints_bpf__attach(struct entrypoints_bpf *skel) -{ - int ret = 0; - - ret = ret < 0 ? ret : entrypoints_bpf__hid_tail_call__attach(skel); - return ret < 0 ? ret : 0; -} - -static inline void -entrypoints_bpf__detach(struct entrypoints_bpf *skel) -{ - skel_closenz(skel->links.hid_tail_call_fd); -} -static void -entrypoints_bpf__destroy(struct entrypoints_bpf *skel) -{ - if (!skel) - return; - entrypoints_bpf__detach(skel); - skel_closenz(skel->progs.hid_tail_call.prog_fd); - skel_closenz(skel->maps.hid_jmp_table.map_fd); - skel_free(skel); -} -static inline struct entrypoints_bpf * -entrypoints_bpf__open(void) -{ - struct entrypoints_bpf *skel; - - skel = skel_alloc(sizeof(*skel)); - if (!skel) - goto cleanup; - skel->ctx.sz = (void *)&skel->links - (void *)skel; - return skel; -cleanup: - entrypoints_bpf__destroy(skel); - return NULL; -} - -static inline int -entrypoints_bpf__load(struct entrypoints_bpf *skel) -{ - struct bpf_load_and_run_opts opts = {}; - int err; - - opts.ctx = (struct bpf_loader_ctx *)skel; - opts.data_sz = 2856; - opts.data = (void *)"\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\ -\x18\0\0\0\0\0\0\0\x60\x02\0\0\x60\x02\0\0\x12\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\ -\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\ -\0\0\x04\0\0\0\x03\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\ -\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\ -\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x04\0\0\0\0\ -\0\0\0\x04\0\0\x04\x20\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\ -\x40\0\0\0\x2a\0\0\0\x07\0\0\0\x80\0\0\0\x33\0\0\0\x07\0\0\0\xc0\0\0\0\x3e\0\0\ -\0\0\0\0\x0e\x09\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x0c\0\0\0\x4c\0\0\0\0\0\0\ -\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x5f\0\0\0\x0b\0\0\0\x63\ -\0\0\0\x01\0\0\x0c\x0d\0\0\0\x09\x01\0\0\x05\0\0\x04\x20\0\0\0\x15\x01\0\0\x10\ -\0\0\0\0\0\0\0\x1b\x01\0\0\x12\0\0\0\x40\0\0\0\x1f\x01\0\0\x10\0\0\0\x80\0\0\0\ -\x2e\x01\0\0\x14\0\0\0\xa0\0\0\0\0\0\0\0\x15\0\0\0\xc0\0\0\0\x3a\x01\0\0\0\0\0\ -\x08\x11\0\0\0\x40\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x13\ -\0\0\0\0\0\0\0\0\0\0\x0a\x1c\0\0\0\x4d\x01\0\0\x04\0\0\x06\x04\0\0\0\x5d\x01\0\ -\0\0\0\0\0\x6e\x01\0\0\x01\0\0\0\x80\x01\0\0\x02\0\0\0\x93\x01\0\0\x03\0\0\0\0\ -\0\0\0\x02\0\0\x05\x04\0\0\0\xa4\x01\0\0\x16\0\0\0\0\0\0\0\xab\x01\0\0\x16\0\0\ -\0\0\0\0\0\xb0\x01\0\0\0\0\0\x08\x02\0\0\0\xec\x01\0\0\0\0\0\x01\x01\0\0\0\x08\ -\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\xf1\x01\0\0\0\ -\0\0\x0e\x18\0\0\0\x01\0\0\0\xf9\x01\0\0\x01\0\0\x0f\x20\0\0\0\x0a\0\0\0\0\0\0\ -\0\x20\0\0\0\xff\x01\0\0\x01\0\0\x0f\x04\0\0\0\x19\0\0\0\0\0\0\0\x04\0\0\0\x07\ -\x02\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\ -\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\x5f\ -\x65\x6e\x74\x72\x69\x65\x73\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\ -\x75\x65\x5f\x73\x69\x7a\x65\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\x62\x6c\ -\x65\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\ -\0\x63\x74\x78\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\x66\x6d\ -\x6f\x64\x5f\x72\x65\x74\x2f\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\ -\x69\x6c\x5f\x63\x61\x6c\x6c\0\x2f\x68\x6f\x6d\x65\x2f\x62\x74\x69\x73\x73\x6f\ -\x69\x72\x2f\x53\x72\x63\x2f\x68\x69\x64\x2f\x64\x72\x69\x76\x65\x72\x73\x2f\ -\x68\x69\x64\x2f\x62\x70\x66\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\ -\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\x2e\x62\x70\x66\x2e\x63\0\x69\ -\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\x28\x68\x69\x64\x5f\x74\x61\x69\ -\x6c\x5f\x63\x61\x6c\x6c\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\x64\x5f\ -\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x68\x69\x64\x5f\x62\ -\x70\x66\x5f\x63\x74\x78\0\x69\x6e\x64\x65\x78\0\x68\x69\x64\0\x61\x6c\x6c\x6f\ -\x63\x61\x74\x65\x64\x5f\x73\x69\x7a\x65\0\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\ -\x70\x65\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\ -\x74\0\x68\x69\x64\x5f\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\x70\x65\0\x48\x49\ -\x44\x5f\x49\x4e\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x4f\ -\x55\x54\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x46\x45\x41\ -\x54\x55\x52\x45\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x52\x45\x50\x4f\ -\x52\x54\x5f\x54\x59\x50\x45\x53\0\x72\x65\x74\x76\x61\x6c\0\x73\x69\x7a\x65\0\ -\x5f\x5f\x73\x33\x32\0\x30\x3a\x30\0\x09\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\ -\x63\x61\x6c\x6c\x28\x63\x74\x78\x2c\x20\x26\x68\x69\x64\x5f\x6a\x6d\x70\x5f\ -\x74\x61\x62\x6c\x65\x2c\x20\x68\x63\x74\x78\x2d\x3e\x69\x6e\x64\x65\x78\x29\ -\x3b\0\x63\x68\x61\x72\0\x4c\x49\x43\x45\x4e\x53\x45\0\x2e\x6d\x61\x70\x73\0\ -\x6c\x69\x63\x65\x6e\x73\x65\0\x68\x69\x64\x5f\x64\x65\x76\x69\x63\x65\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8a\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\ -\0\0\0\x04\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\ -\x6a\x6d\x70\x5f\x74\x61\x62\x6c\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\ -\0\0\x18\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\ -\x95\0\0\0\0\0\0\0\0\0\0\0\x0e\0\0\0\0\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\ -\x01\0\0\0\x8e\0\0\0\xba\x01\0\0\x02\x50\0\0\x05\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\ -\x48\0\0\x08\0\0\0\x0f\0\0\0\xb6\x01\0\0\0\0\0\0\x1a\0\0\0\x07\0\0\0\0\0\0\0\0\ -\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\ -\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\0\0\0\0\x1a\0\0\0\0\0\0\0\ -\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\ -\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\ -\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\ -\0\0"; - opts.insns_sz = 1192; - opts.insns = (void *)"\ -\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\ -\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\ -\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\ -\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\ -\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\ -\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\ -\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\ -\0\0\0\0\0\xa8\x09\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\ -\0\0\0\0\0\0\0\xa4\x09\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\ -\0\0\0\0\0\0\0\0\0\x98\x09\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\ -\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\ -\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\xb7\x03\0\0\x1c\0\0\0\ -\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\ -\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\ -\0\0\xbc\x09\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\ -\0\0\0\xb0\x09\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\ -\0\xc5\x07\xca\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\ -\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\x09\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\ -\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x0a\0\0\x18\x61\0\0\ -\0\0\0\0\0\0\0\0\x88\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\ -\x38\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\ -\x60\0\0\0\0\0\0\0\0\0\0\x40\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x0a\0\0\ -\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x0a\0\0\x18\x61\0\0\0\0\0\ -\0\0\0\0\0\0\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ -\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\ -\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x0a\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\ -\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0a\0\0\x63\x01\0\0\0\0\0\0\x79\x60\ -\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\ -\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0a\0\0\x63\x01\0\0\0\0\0\ -\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0b\0\0\xb7\x02\0\0\x14\0\0\0\xb7\x03\0\0\ -\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\ -\x91\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0a\0\0\x63\x70\x6c\0\0\0\0\0\ -\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\ -\0\0\0\0\0\0\0\0\x80\x0a\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\ -\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf0\x0a\0\0\x61\x01\0\0\0\0\0\0\xd5\ -\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x7f\xff\0\0\ -\0\0\x63\x7a\x80\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\ -\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\ -\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\ -\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0"; - err = bpf_load_and_run(&opts); - if (err < 0) - return err; - return 0; -} - -static inline struct entrypoints_bpf * -entrypoints_bpf__open_and_load(void) -{ - struct entrypoints_bpf *skel; - - skel = entrypoints_bpf__open(); - if (!skel) - return NULL; - if (entrypoints_bpf__load(skel)) { - entrypoints_bpf__destroy(skel); - return NULL; - } - return skel; -} - -__attribute__((unused)) static void -entrypoints_bpf__assert(struct entrypoints_bpf *s __attribute__((unused))) -{ -#ifdef __cplusplus -#define _Static_assert static_assert -#endif -#ifdef __cplusplus -#undef _Static_assert -#endif -} - -#endif /* __ENTRYPOINTS_BPF_SKEL_H__ */ diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 7216c3c7713d..06cc628e7bb4 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -3,7 +3,7 @@ /* * HID-BPF support for Linux * - * Copyright (c) 2022 Benjamin Tissoires + * Copyright (c) 2022-2024 Benjamin Tissoires */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -17,34 +17,11 @@ #include #include #include -#include #include "hid_bpf_dispatch.h" -#include "entrypoints/entrypoints.lskel.h" struct hid_ops *hid_ops; EXPORT_SYMBOL(hid_ops); -/** - * hid_bpf_device_event - Called whenever an event is coming in from the device - * - * @ctx: The HID-BPF context - * - * @return %0 on success and keep processing; a positive value to change the - * incoming size buffer; a negative error code to interrupt the processing - * of this event - * - * Declare an %fmod_ret tracing bpf program to this function and attach this - * program through hid_bpf_attach_prog() to have this helper called for - * any incoming event from the device itself. - * - * The function is called while on IRQ context, so we can not sleep. - */ -/* never used by the kernel but declared so we can load and attach a tracepoint */ -__weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx) -{ - return 0; -} - u8 * dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data, u32 *size, int interrupt) @@ -52,7 +29,6 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type struct hid_bpf_ctx_kern ctx_kern = { .ctx = { .hid = hdev, - .report_type = type, .allocated_size = hdev->bpf.allocated_data, .size = *size, }, @@ -86,11 +62,6 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type } rcu_read_unlock(); - ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern); - if (ret < 0) - return ERR_PTR(ret); - ret = ctx_kern.ctx.retval; - if (ret) { if (ret > ctx_kern.ctx.allocated_size) return ERR_PTR(-EINVAL); @@ -102,26 +73,6 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type } EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event); -/** - * hid_bpf_rdesc_fixup - Called when the probe function parses the report - * descriptor of the HID device - * - * @ctx: The HID-BPF context - * - * @return 0 on success and keep processing; a positive value to change the - * incoming size buffer; a negative error code to interrupt the processing - * of this event - * - * Declare an %fmod_ret tracing bpf program to this function and attach this - * program through hid_bpf_attach_prog() to have this helper called before any - * parsing of the report descriptor by HID. - */ -/* never used by the kernel but declared so we can load and attach a tracepoint */ -__weak noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx) -{ - return 0; -} - u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size) { int ret; @@ -133,16 +84,16 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s }, }; + 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)); - if (hdev->bpf.rdesc_ops) - ret = hdev->bpf.rdesc_ops->hid_rdesc_fixup(&ctx_kern.ctx); - else - ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern); + ret = hdev->bpf.rdesc_ops->hid_rdesc_fixup(&ctx_kern.ctx); if (ret < 0) goto ignore_bpf; @@ -242,39 +193,6 @@ int hid_bpf_reconnect(struct hid_device *hdev) return 0; } -static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog, - __u32 flags) -{ - int fd, err, prog_type; - - prog_type = hid_bpf_get_prog_attach_type(prog); - if (prog_type < 0) - return prog_type; - - if (prog_type >= HID_BPF_PROG_TYPE_MAX) - return -EINVAL; - - if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { - err = hid_bpf_allocate_event_data(hdev); - if (err) - return err; - } - - fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags); - if (fd < 0) - return fd; - - if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { - err = hid_bpf_reconnect(hdev); - if (err) { - close_fd(fd); - return err; - } - } - - return fd; -} - /* Disables missing prototype warnings */ __bpf_kfunc_start_defs(); @@ -303,57 +221,6 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr return ctx_kern->data + offset; } -/** - * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device - * - * @hid_id: the system unique identifier of the HID device - * @prog_fd: an fd in the user process representing the program to attach - * @flags: any logical OR combination of &enum hid_bpf_attach_flags - * - * @returns an fd of a bpf_link object on success (> %0), an error code otherwise. - * Closing this fd will detach the program from the HID device (unless the bpf_link - * is pinned to the BPF file system). - */ -/* called from syscall */ -__bpf_kfunc int -hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) -{ - struct hid_device *hdev; - struct bpf_prog *prog; - int err, fd; - - if ((flags & ~HID_BPF_FLAG_MASK)) - return -EINVAL; - - hdev = hid_get_device(hid_id); - if (IS_ERR(hdev)) - return PTR_ERR(hdev); - - /* - * take a ref on the prog itself, it will be released - * on errors or when it'll be detached - */ - prog = bpf_prog_get(prog_fd); - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto out_dev_put; - } - - fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags); - if (fd < 0) { - err = fd; - goto out_prog_put; - } - - return fd; - - out_prog_put: - bpf_prog_put(prog); - out_dev_put: - hid_put_device(hdev); - return err; -} - /** * hid_bpf_allocate_context - Allocate a context to the given HID device * @@ -583,21 +450,8 @@ static const struct btf_kfunc_id_set hid_bpf_kfunc_set = { .set = &hid_bpf_kfunc_ids, }; -/* our HID-BPF entrypoints */ -BTF_SET8_START(hid_bpf_fmodret_ids) -BTF_ID_FLAGS(func, hid_bpf_device_event) -BTF_ID_FLAGS(func, hid_bpf_rdesc_fixup) -BTF_ID_FLAGS(func, __hid_bpf_tail_call) -BTF_SET8_END(hid_bpf_fmodret_ids) - -static const struct btf_kfunc_id_set hid_bpf_fmodret_set = { - .owner = THIS_MODULE, - .set = &hid_bpf_fmodret_ids, -}; - /* for syscall HID-BPF */ BTF_KFUNCS_START(hid_bpf_syscall_kfunc_ids) -BTF_ID_FLAGS(func, hid_bpf_attach_prog) BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE) BTF_ID_FLAGS(func, hid_bpf_hw_request) @@ -622,8 +476,6 @@ int hid_bpf_connect_device(struct hid_device *hdev) break; } } - if (rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT])) - need_to_allocate = true; rcu_read_unlock(); /* only allocate BPF data if there are programs attached */ @@ -650,14 +502,12 @@ void hid_bpf_destroy_device(struct hid_device *hdev) /* mark the device as destroyed in bpf so we don't reattach it */ hdev->bpf.destroyed = true; - __hid_bpf_destroy_device(hdev); __hid_bpf_ops_destroy_device(hdev); } EXPORT_SYMBOL_GPL(hid_bpf_destroy_device); void hid_bpf_device_init(struct hid_device *hdev) { - spin_lock_init(&hdev->bpf.progs_lock); INIT_LIST_HEAD(&hdev->bpf.prog_list); mutex_init(&hdev->bpf.prog_list_lock); } @@ -670,37 +520,15 @@ static int __init hid_bpf_init(void) /* 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: the syscall allowing to attach a BPF program to a HID device - * will not be available, so nobody will be able to use the functionality. + * This is not a big deal: nobody will be able to use the functionality. */ - err = register_btf_fmodret_id_set(&hid_bpf_fmodret_set); - if (err) { - pr_warn("error while registering fmodret entrypoints: %d", err); - return 0; - } - - err = hid_bpf_preload_skel(); - if (err) { - pr_warn("error while preloading HID BPF dispatcher: %d", err); - return 0; - } - - /* register tracing kfuncs after we are sure we can load our preloaded bpf program */ - err = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &hid_bpf_kfunc_set); - if (err) { - pr_warn("error while setting HID BPF tracing kfuncs: %d", err); - return 0; - } - - /* register struct_ops kfuncs after we are sure we can load our preloaded bpf program */ 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; } - /* register syscalls after we are sure we can load our preloaded bpf program */ 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); @@ -710,15 +538,6 @@ static int __init hid_bpf_init(void) return 0; } -static void __exit hid_bpf_exit(void) -{ - /* HID depends on us, so if we hit that code, we are guaranteed that hid - * has been removed and thus we do not need to clear the HID devices - */ - hid_bpf_free_links_and_skel(); -} - late_initcall(hid_bpf_init); -module_exit(hid_bpf_exit); 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 index e52c43d81650..835e6f69f479 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.h +++ b/drivers/hid/bpf/hid_bpf_dispatch.h @@ -13,15 +13,7 @@ struct hid_bpf_ctx_kern { 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); -int hid_bpf_preload_skel(void); -void hid_bpf_free_links_and_skel(void); -int hid_bpf_get_prog_attach_type(struct bpf_prog *prog); -int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd, - struct bpf_prog *prog, __u32 flags); -void __hid_bpf_destroy_device(struct hid_device *hdev); void __hid_bpf_ops_destroy_device(struct hid_device *hdev); -int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, - struct hid_bpf_ctx_kern *ctx_kern); int hid_bpf_reconnect(struct hid_device *hdev); struct bpf_prog; diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c deleted file mode 100644 index 8a54ba447718..000000000000 --- a/drivers/hid/bpf/hid_bpf_jmp_table.c +++ /dev/null @@ -1,568 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * HID-BPF support for Linux - * - * Copyright (c) 2022 Benjamin Tissoires - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hid_bpf_dispatch.h" -#include "entrypoints/entrypoints.lskel.h" - -#define HID_BPF_MAX_PROGS 1024 /* keep this in sync with preloaded bpf, - * needs to be a power of 2 as we use it as - * a circular buffer - */ - -#define NEXT(idx) (((idx) + 1) & (HID_BPF_MAX_PROGS - 1)) -#define PREV(idx) (((idx) - 1) & (HID_BPF_MAX_PROGS - 1)) - -/* - * represents one attached program stored in the hid jump table - */ -struct hid_bpf_prog_entry { - struct bpf_prog *prog; - struct hid_device *hdev; - enum hid_bpf_prog_type type; - u16 idx; -}; - -struct hid_bpf_jmp_table { - struct bpf_map *map; - struct hid_bpf_prog_entry entries[HID_BPF_MAX_PROGS]; /* compacted list, circular buffer */ - int tail, head; - struct bpf_prog *progs[HID_BPF_MAX_PROGS]; /* idx -> progs mapping */ - unsigned long enabled[BITS_TO_LONGS(HID_BPF_MAX_PROGS)]; -}; - -#define FOR_ENTRIES(__i, __start, __end) \ - for (__i = __start; CIRC_CNT(__end, __i, HID_BPF_MAX_PROGS); __i = NEXT(__i)) - -static struct hid_bpf_jmp_table jmp_table; - -static DEFINE_MUTEX(hid_bpf_attach_lock); /* held when attaching/detaching programs */ - -static void hid_bpf_release_progs(struct work_struct *work); - -static DECLARE_WORK(release_work, hid_bpf_release_progs); - -BTF_ID_LIST(hid_bpf_btf_ids) -BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */ -BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */ - -static int hid_bpf_max_programs(enum hid_bpf_prog_type type) -{ - switch (type) { - case HID_BPF_PROG_TYPE_DEVICE_EVENT: - return HID_BPF_MAX_PROGS_PER_DEV; - case HID_BPF_PROG_TYPE_RDESC_FIXUP: - return 1; - default: - return -EINVAL; - } -} - -static int hid_bpf_program_count(struct hid_device *hdev, - struct bpf_prog *prog, - enum hid_bpf_prog_type type) -{ - int i, n = 0; - - if (type >= HID_BPF_PROG_TYPE_MAX) - return -EINVAL; - - if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && hdev->bpf.rdesc_ops) - n += 1; - - FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { - struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; - - if (type != HID_BPF_PROG_TYPE_UNDEF && entry->type != type) - continue; - - if (hdev && entry->hdev != hdev) - continue; - - if (prog && entry->prog != prog) - continue; - - n++; - } - - return n; -} - -__weak noinline int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx) -{ - return 0; -} - -int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, - struct hid_bpf_ctx_kern *ctx_kern) -{ - struct hid_bpf_prog_list *prog_list; - int i, idx, err = 0; - - rcu_read_lock(); - prog_list = rcu_dereference(hdev->bpf.progs[type]); - - if (!prog_list) - goto out_unlock; - - for (i = 0; i < prog_list->prog_cnt; i++) { - idx = prog_list->prog_idx[i]; - - if (!test_bit(idx, jmp_table.enabled)) - continue; - - ctx_kern->ctx.index = idx; - err = __hid_bpf_tail_call(&ctx_kern->ctx); - if (err < 0) - break; - if (err) - ctx_kern->ctx.retval = err; - } - - out_unlock: - rcu_read_unlock(); - - return err; -} - -/* - * assign the list of programs attached to a given hid device. - */ -static void __hid_bpf_set_hdev_progs(struct hid_device *hdev, struct hid_bpf_prog_list *new_list, - enum hid_bpf_prog_type type) -{ - struct hid_bpf_prog_list *old_list; - - spin_lock(&hdev->bpf.progs_lock); - old_list = rcu_dereference_protected(hdev->bpf.progs[type], - lockdep_is_held(&hdev->bpf.progs_lock)); - rcu_assign_pointer(hdev->bpf.progs[type], new_list); - spin_unlock(&hdev->bpf.progs_lock); - synchronize_rcu(); - - kfree(old_list); -} - -/* - * allocate and populate the list of programs attached to a given hid device. - * - * Must be called under lock. - */ -static int hid_bpf_populate_hdev(struct hid_device *hdev, enum hid_bpf_prog_type type) -{ - struct hid_bpf_prog_list *new_list; - int i; - - if (type >= HID_BPF_PROG_TYPE_MAX || !hdev) - return -EINVAL; - - if (hdev->bpf.destroyed) - return 0; - - new_list = kzalloc(sizeof(*new_list), GFP_KERNEL); - if (!new_list) - return -ENOMEM; - - FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { - struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; - - if (entry->type == type && entry->hdev == hdev && - test_bit(entry->idx, jmp_table.enabled)) - new_list->prog_idx[new_list->prog_cnt++] = entry->idx; - } - - __hid_bpf_set_hdev_progs(hdev, new_list, type); - - return 0; -} - -static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx) -{ - skel_map_delete_elem(map_fd, &idx); - jmp_table.progs[idx] = NULL; -} - -static void hid_bpf_release_progs(struct work_struct *work) -{ - int i, j, n, map_fd = -1; - bool hdev_destroyed; - - if (!jmp_table.map) - return; - - /* retrieve a fd of our prog_array map in BPF */ - map_fd = skel_map_get_fd_by_id(jmp_table.map->id); - if (map_fd < 0) - return; - - mutex_lock(&hid_bpf_attach_lock); /* protects against attaching new programs */ - - /* detach unused progs from HID devices */ - FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { - struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; - enum hid_bpf_prog_type type; - struct hid_device *hdev; - - if (test_bit(entry->idx, jmp_table.enabled)) - continue; - - /* we have an attached prog */ - if (entry->hdev) { - hdev = entry->hdev; - type = entry->type; - /* - * hdev is still valid, even if we are called after hid_destroy_device(): - * when hid_bpf_attach() gets called, it takes a ref on the dev through - * bus_find_device() - */ - hdev_destroyed = hdev->bpf.destroyed; - - hid_bpf_populate_hdev(hdev, type); - - /* mark all other disabled progs from hdev of the given type as detached */ - FOR_ENTRIES(j, i, jmp_table.head) { - struct hid_bpf_prog_entry *next; - - next = &jmp_table.entries[j]; - - if (test_bit(next->idx, jmp_table.enabled)) - continue; - - if (next->hdev == hdev && next->type == type) { - /* - * clear the hdev reference and decrement the device ref - * that was taken during bus_find_device() while calling - * hid_bpf_attach() - */ - next->hdev = NULL; - put_device(&hdev->dev); - } - } - - /* if type was rdesc fixup and the device is not gone, reconnect device */ - if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed) - hid_bpf_reconnect(hdev); - } - } - - /* remove all unused progs from the jump table */ - FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { - struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; - - if (test_bit(entry->idx, jmp_table.enabled)) - continue; - - if (entry->prog) - __hid_bpf_do_release_prog(map_fd, entry->idx); - } - - /* compact the entry list */ - n = jmp_table.tail; - FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) { - struct hid_bpf_prog_entry *entry = &jmp_table.entries[i]; - - if (!test_bit(entry->idx, jmp_table.enabled)) - continue; - - jmp_table.entries[n] = jmp_table.entries[i]; - n = NEXT(n); - } - - jmp_table.head = n; - - mutex_unlock(&hid_bpf_attach_lock); - - if (map_fd >= 0) - close_fd(map_fd); -} - -static void hid_bpf_release_prog_at(int idx) -{ - int map_fd = -1; - - /* retrieve a fd of our prog_array map in BPF */ - map_fd = skel_map_get_fd_by_id(jmp_table.map->id); - if (map_fd < 0) - return; - - __hid_bpf_do_release_prog(map_fd, idx); - - close(map_fd); -} - -/* - * Insert the given BPF program represented by its fd in the jmp table. - * Returns the index in the jump table or a negative error. - */ -static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog) -{ - int i, index = -1, map_fd = -1, err = -EINVAL; - - /* retrieve a fd of our prog_array map in BPF */ - map_fd = skel_map_get_fd_by_id(jmp_table.map->id); - - if (map_fd < 0) { - err = -EINVAL; - goto out; - } - - /* find the first available index in the jmp_table */ - for (i = 0; i < HID_BPF_MAX_PROGS; i++) { - if (!jmp_table.progs[i] && index < 0) { - /* mark the index as used */ - jmp_table.progs[i] = prog; - index = i; - __set_bit(i, jmp_table.enabled); - } - } - if (index < 0) { - err = -ENOMEM; - goto out; - } - - /* insert the program in the jump table */ - err = skel_map_update_elem(map_fd, &index, &prog_fd, 0); - if (err) - goto out; - - /* return the index */ - err = index; - - out: - if (err < 0) - __hid_bpf_do_release_prog(map_fd, index); - if (map_fd >= 0) - close_fd(map_fd); - return err; -} - -int hid_bpf_get_prog_attach_type(struct bpf_prog *prog) -{ - int prog_type = HID_BPF_PROG_TYPE_UNDEF; - int i; - - for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) { - if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) { - prog_type = i; - break; - } - } - - return prog_type; -} - -static void hid_bpf_link_release(struct bpf_link *link) -{ - struct hid_bpf_link *hid_link = - container_of(link, struct hid_bpf_link, link); - - __clear_bit(hid_link->hid_table_index, jmp_table.enabled); - schedule_work(&release_work); -} - -static void hid_bpf_link_dealloc(struct bpf_link *link) -{ - struct hid_bpf_link *hid_link = - container_of(link, struct hid_bpf_link, link); - - kfree(hid_link); -} - -static void hid_bpf_link_show_fdinfo(const struct bpf_link *link, - struct seq_file *seq) -{ - seq_printf(seq, - "attach_type:\tHID-BPF\n"); -} - -static const struct bpf_link_ops hid_bpf_link_lops = { - .release = hid_bpf_link_release, - .dealloc = hid_bpf_link_dealloc, - .show_fdinfo = hid_bpf_link_show_fdinfo, -}; - -/* called from syscall */ -noinline int -__hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, - int prog_fd, struct bpf_prog *prog, __u32 flags) -{ - struct bpf_link_primer link_primer; - struct hid_bpf_link *link; - struct hid_bpf_prog_entry *prog_entry; - int cnt, err = -EINVAL, prog_table_idx = -1; - - mutex_lock(&hid_bpf_attach_lock); - - link = kzalloc(sizeof(*link), GFP_USER); - if (!link) { - err = -ENOMEM; - goto err_unlock; - } - - bpf_link_init(&link->link, BPF_LINK_TYPE_UNSPEC, - &hid_bpf_link_lops, prog); - - /* do not attach too many programs to a given HID device */ - cnt = hid_bpf_program_count(hdev, NULL, prog_type); - if (cnt < 0) { - err = cnt; - goto err_unlock; - } - - if (cnt >= hid_bpf_max_programs(prog_type)) { - err = -E2BIG; - goto err_unlock; - } - - prog_table_idx = hid_bpf_insert_prog(prog_fd, prog); - /* if the jmp table is full, abort */ - if (prog_table_idx < 0) { - err = prog_table_idx; - goto err_unlock; - } - - if (flags & HID_BPF_FLAG_INSERT_HEAD) { - /* take the previous prog_entry slot */ - jmp_table.tail = PREV(jmp_table.tail); - prog_entry = &jmp_table.entries[jmp_table.tail]; - } else { - /* take the next prog_entry slot */ - prog_entry = &jmp_table.entries[jmp_table.head]; - jmp_table.head = NEXT(jmp_table.head); - } - - /* we steal the ref here */ - prog_entry->prog = prog; - prog_entry->idx = prog_table_idx; - prog_entry->hdev = hdev; - prog_entry->type = prog_type; - - /* finally store the index in the device list */ - err = hid_bpf_populate_hdev(hdev, prog_type); - if (err) { - hid_bpf_release_prog_at(prog_table_idx); - goto err_unlock; - } - - link->hid_table_index = prog_table_idx; - - err = bpf_link_prime(&link->link, &link_primer); - if (err) - goto err_unlock; - - mutex_unlock(&hid_bpf_attach_lock); - - return bpf_link_settle(&link_primer); - - err_unlock: - mutex_unlock(&hid_bpf_attach_lock); - - kfree(link); - - return err; -} - -void __hid_bpf_destroy_device(struct hid_device *hdev) -{ - int type, i; - struct hid_bpf_prog_list *prog_list; - - rcu_read_lock(); - - for (type = 0; type < HID_BPF_PROG_TYPE_MAX; type++) { - prog_list = rcu_dereference(hdev->bpf.progs[type]); - - if (!prog_list) - continue; - - for (i = 0; i < prog_list->prog_cnt; i++) - __clear_bit(prog_list->prog_idx[i], jmp_table.enabled); - } - - rcu_read_unlock(); - - for (type = 0; type < HID_BPF_PROG_TYPE_MAX; type++) - __hid_bpf_set_hdev_progs(hdev, NULL, type); - - /* schedule release of all detached progs */ - schedule_work(&release_work); -} - -#define HID_BPF_PROGS_COUNT 1 - -static struct bpf_link *links[HID_BPF_PROGS_COUNT]; -static struct entrypoints_bpf *skel; - -void hid_bpf_free_links_and_skel(void) -{ - int i; - - /* the following is enough to release all programs attached to hid */ - if (jmp_table.map) - bpf_map_put_with_uref(jmp_table.map); - - for (i = 0; i < ARRAY_SIZE(links); i++) { - if (!IS_ERR_OR_NULL(links[i])) - bpf_link_put(links[i]); - } - entrypoints_bpf__destroy(skel); -} - -#define ATTACH_AND_STORE_LINK(__name) do { \ - err = entrypoints_bpf__##__name##__attach(skel); \ - if (err) \ - goto out; \ - \ - links[idx] = bpf_link_get_from_fd(skel->links.__name##_fd); \ - if (IS_ERR(links[idx])) { \ - err = PTR_ERR(links[idx]); \ - goto out; \ - } \ - \ - /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out \ - * makes skel_closenz() a no-op later in iterators_bpf__destroy(). \ - */ \ - close_fd(skel->links.__name##_fd); \ - skel->links.__name##_fd = 0; \ - idx++; \ -} while (0) - -int hid_bpf_preload_skel(void) -{ - int err, idx = 0; - - skel = entrypoints_bpf__open(); - if (!skel) - return -ENOMEM; - - err = entrypoints_bpf__load(skel); - if (err) - goto out; - - jmp_table.map = bpf_map_get_with_uref(skel->maps.hid_jmp_table.map_fd); - if (IS_ERR(jmp_table.map)) { - err = PTR_ERR(jmp_table.map); - goto out; - } - - ATTACH_AND_STORE_LINK(hid_tail_call); - - return 0; -out: - hid_bpf_free_links_and_skel(); - return err; -} diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index c4f4ce10b7dd..447b94aa99ab 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -4,7 +4,7 @@ #define __HID_BPF_H #include -#include +#include #include struct hid_device; @@ -24,11 +24,7 @@ struct hid_device; * * All of these fields are currently read-only. * - * @index: program index in the jump table. No special meaning (a smaller index - * doesn't mean the program will be executed before another program with - * a bigger index). * @hid: the ``struct hid_device`` representing the device itself - * @report_type: used for ``hid_bpf_device_event()`` * @allocated_size: Allocated size of data. * * This is how much memory is available and can be requested @@ -47,54 +43,21 @@ struct hid_device; * @retval: Return value of the previous program. */ struct hid_bpf_ctx { - __u32 index; const struct hid_device *hid; __u32 allocated_size; - enum hid_report_type report_type; union { __s32 retval; __s32 size; }; }; -/** - * enum hid_bpf_attach_flags - flags used when attaching a HIF-BPF program - * - * @HID_BPF_FLAG_NONE: no specific flag is used, the kernel choses where to - * insert the program - * @HID_BPF_FLAG_INSERT_HEAD: insert the given program before any other program - * currently attached to the device. This doesn't - * guarantee that this program will always be first - */ -enum hid_bpf_attach_flags { - HID_BPF_FLAG_NONE = 0, - HID_BPF_FLAG_INSERT_HEAD = _BITUL(0), - - /* private: internal use only */ - HID_BPF_FLAG_MAX, -}; - -/* Following functions are tracepoints that BPF programs can attach to */ -int hid_bpf_device_event(struct hid_bpf_ctx *ctx); -int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx); - /* * Below is HID internal */ -/* internal function to call eBPF programs, not to be used by anybody */ -int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx); - #define HID_BPF_MAX_PROGS_PER_DEV 64 #define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1) -/* types of HID programs to attach to */ -enum hid_bpf_prog_type { - HID_BPF_PROG_TYPE_UNDEF = -1, - HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */ - HID_BPF_PROG_TYPE_RDESC_FIXUP, - HID_BPF_PROG_TYPE_MAX, -}; struct hid_report_enum; @@ -167,11 +130,6 @@ struct hid_bpf_ops { struct hid_device *hdev; }; -struct hid_bpf_prog_list { - u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV]; - u8 prog_cnt; -}; - /* stored in each device */ struct hid_bpf { u8 *device_data; /* allocated when a bpf program of type @@ -179,23 +137,13 @@ struct hid_bpf { * to this HID device */ u32 allocated_data; - - struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */ bool destroyed; /* prevents the assignment of any progs */ - spinlock_t progs_lock; /* protects RCU update of progs */ - struct hid_bpf_ops *rdesc_ops; struct list_head prog_list; struct mutex prog_list_lock; /* protects prog_list update */ }; -/* specific HID-BPF link when a program is attached to a device */ -struct hid_bpf_link { - struct bpf_link link; - int hid_table_index; -}; - #ifdef CONFIG_HID_BPF u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 *size, int interrupt); From 05b3b8f19441b6bf039cec1990de3c75bb9dbbd9 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:21 +0200 Subject: [PATCH 20/60] selftests/hid: add subprog call test I got a weird verifier error with a subprog once, so let's have a test for it. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-9-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 41 +++++++++++++++++++++++++ tools/testing/selftests/hid/progs/hid.c | 24 +++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index 967dfe6b58cb..45e173db35bd 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -638,6 +638,47 @@ TEST_F(hid_bpf, raw_event) ASSERT_EQ(buf[2], 52); } +/* + * Attach hid_first_event to the given uhid device, + * retrieve and open the matching hidraw node, + * inject one event in the uhid device, + * check that the program sees it and can change the data + */ +TEST_F(hid_bpf, subprog_raw_event) +{ + const struct test_program progs[] = { + { .name = "hid_subprog_first_event" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* inject one event */ + buf[0] = 1; + buf[1] = 42; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[2], 47); + + /* inject another event */ + memset(buf, 0, sizeof(buf)); + buf[0] = 1; + buf[1] = 47; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[2], 52); +} + /* * Ensures that we can attach/detach programs */ diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index 614f1aa32649..2e7e5a736dc6 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -35,6 +35,30 @@ struct hid_bpf_ops first_event = { .hid_id = 2, }; +int __hid_subprog_first_event(struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) +{ + __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); + + if (!rw_data) + return 0; /* EPERM check */ + + rw_data[2] = rw_data[1] + 5; + + return hid_ctx->size; +} + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_subprog_first_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) +{ + return __hid_subprog_first_event(hid_ctx, type); +} + +SEC(".struct_ops.link") +struct hid_bpf_ops subprog_first_event = { + .hid_device_event = (void *)hid_subprog_first_event, + .hid_id = 2, +}; + SEC("?struct_ops/hid_device_event") int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) { From c5958697a5fa29d3ba9332205a88725afe9ed912 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:22 +0200 Subject: [PATCH 21/60] Documentation: HID: amend HID-BPF for struct_ops Now that we are using struct_ops, the docs need to be changed. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-10-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- Documentation/hid/hid-bpf.rst | 156 ++++++++++++++++------------------ include/linux/hid_bpf.h | 8 +- 2 files changed, 76 insertions(+), 88 deletions(-) diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst index 0765b3298ecf..456e15097d87 100644 --- a/Documentation/hid/hid-bpf.rst +++ b/Documentation/hid/hid-bpf.rst @@ -132,16 +132,17 @@ input events. Available types of programs =========================== -HID-BPF is built "on top" of BPF, meaning that we use tracing method to +HID-BPF is built "on top" of BPF, meaning that we use bpf struct_ops method to declare our programs. HID-BPF has the following attachment types available: -1. event processing/filtering with ``SEC("fmod_ret/hid_bpf_device_event")`` in libbpf +1. event processing/filtering with ``SEC("struct_ops/hid_device_event")`` in libbpf 2. actions coming from userspace with ``SEC("syscall")`` in libbpf -3. change of the report descriptor with ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` in libbpf +3. change of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or + ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpf -A ``hid_bpf_device_event`` is calling a BPF program when an event is received from +A ``hid_device_event`` is calling a BPF program when an event is received from the device. Thus we are in IRQ context and can act on the data or notify userspace. And given that we are in IRQ context, we can not talk back to the device. @@ -149,37 +150,42 @@ A ``syscall`` means that userspace called the syscall ``BPF_PROG_RUN`` facility. This time, we can do any operations allowed by HID-BPF, and talking to the device is allowed. -Last, ``hid_bpf_rdesc_fixup`` is different from the others as there can be only one +Last, ``hid_rdesc_fixup`` is different from the others as there can be only one BPF program of this type. This is called on ``probe`` from the driver and allows to -change the report descriptor from the BPF program. Once a ``hid_bpf_rdesc_fixup`` +change the report descriptor from the BPF program. Once a ``hid_rdesc_fixup`` program has been loaded, it is not possible to overwrite it unless the program which inserted it allows us by pinning the program and closing all of its fds pointing to it. +Note that ``hid_rdesc_fixup`` can be declared as sleepable (``SEC("struct_ops.s/hid_rdesc_fixup")``). + + Developer API: ============== +Available ``struct_ops`` for HID-BPF: +------------------------------------- + +.. kernel-doc:: include/linux/hid_bpf.h + :identifiers: hid_bpf_ops + + User API data structures available in programs: ----------------------------------------------- .. kernel-doc:: include/linux/hid_bpf.h + :identifiers: hid_bpf_ctx -Available tracing functions to attach a HID-BPF program: --------------------------------------------------------- +Available API that can be used in all HID-BPF struct_ops programs: +------------------------------------------------------------------ .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c - :functions: hid_bpf_device_event hid_bpf_rdesc_fixup + :identifiers: hid_bpf_get_data -Available API that can be used in all HID-BPF programs: -------------------------------------------------------- +Available API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs: +------------------------------------------------------------------------------------------------------- .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c - :functions: hid_bpf_get_data - -Available API that can be used in syscall HID-BPF programs: ------------------------------------------------------------ - -.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c - :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context + :identifiers: hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context General overview of a HID-BPF program ===================================== @@ -222,20 +228,21 @@ This allows the following: Effect of a HID-BPF program --------------------------- -For all HID-BPF attachment types except for :c:func:`hid_bpf_rdesc_fixup`, several eBPF -programs can be attached to the same device. +For all HID-BPF attachment types except for :c:func:`hid_rdesc_fixup`, several eBPF +programs can be attached to the same device. If a HID-BPF struct_ops has a +:c:func:`hid_rdesc_fixup` while another is already attached to the device, the +kernel will return `-EINVAL` when attaching the struct_ops. -Unless ``HID_BPF_FLAG_INSERT_HEAD`` is added to the flags while attaching the -program, the new program is appended at the end of the list. -``HID_BPF_FLAG_INSERT_HEAD`` will insert the new program at the beginning of the -list which is useful for e.g. tracing where we need to get the unprocessed events -from the device. +Unless ``BPF_F_BEFORE`` is added to the flags while attaching the program, the new +program is appended at the end of the list. +``BPF_F_BEFORE`` will insert the new program at the beginning of the list which is +useful for e.g. tracing where we need to get the unprocessed events from the device. -Note that if there are multiple programs using the ``HID_BPF_FLAG_INSERT_HEAD`` flag, +Note that if there are multiple programs using the ``BPF_F_BEFORE`` flag, only the most recently loaded one is actually the first in the list. -``SEC("fmod_ret/hid_bpf_device_event")`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``SEC("struct_ops/hid_device_event")`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whenever a matching event is raised, the eBPF programs are called one after the other and are working on the same data buffer. @@ -258,17 +265,17 @@ with, userspace needs to refer to the device by its unique system id (the last 4 in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``). To retrieve a context associated with the device, the program must call -:c:func:`hid_bpf_allocate_context` and must release it with :c:func:`hid_bpf_release_context` +hid_bpf_allocate_context() and must release it with hid_bpf_release_context() before returning. Once the context is retrieved, one can also request a pointer to kernel memory with -:c:func:`hid_bpf_get_data`. This memory is big enough to support all input/output/feature +hid_bpf_get_data(). This memory is big enough to support all input/output/feature reports of the given device. -``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``SEC("struct_ops/hid_rdesc_fixup")`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``hid_bpf_rdesc_fixup`` program works in a similar manner to -``.report_fixup`` of ``struct hid_driver``. +The ``hid_rdesc_fixup`` program works in a similar manner to ``.report_fixup`` +of ``struct hid_driver``. When the device is probed, the kernel sets the data buffer of the context with the content of the report descriptor. The memory associated with that buffer is @@ -277,33 +284,31 @@ content of the report descriptor. The memory associated with that buffer is The eBPF program can modify the data buffer at-will and the kernel uses the modified content and size as the report descriptor. -Whenever a ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` program is attached (if no -program was attached before), the kernel immediately disconnects the HID device -and does a reprobe. +Whenever a struct_ops containing a ``SEC("struct_ops/hid_rdesc_fixup")`` program +is attached (if no program was attached before), the kernel immediately disconnects +the HID device and does a reprobe. -In the same way, when the ``SEC("fmod_ret/hid_bpf_rdesc_fixup")`` program is -detached, the kernel issues a disconnect on the device. +In the same way, when this struct_ops is detached, the kernel issues a disconnect +on the device. There is no ``detach`` facility in HID-BPF. Detaching a program happens when -all the user space file descriptors pointing at a program are closed. +all the user space file descriptors pointing at a HID-BPF struct_ops link are closed. Thus, if we need to replace a report descriptor fixup, some cooperation is required from the owner of the original report descriptor fixup. -The previous owner will likely pin the program in the bpffs, and we can then +The previous owner will likely pin the struct_ops link in the bpffs, and we can then replace it through normal bpf operations. Attaching a bpf program to a device =================================== -``libbpf`` does not export any helper to attach a HID-BPF program. -Users need to use a dedicated ``syscall`` program which will call -``hid_bpf_attach_prog(hid_id, program_fd, flags)``. +We now use standard struct_ops attachment through ``bpf_map__attach_struct_ops()``. +But given that we need to attach a struct_ops to a dedicated HID device, the caller +must set ``hid_id`` in the struct_ops map before loading the program in the kernel. ``hid_id`` is the unique system ID of the HID device (the last 4 numbers in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``) -``progam_fd`` is the opened file descriptor of the program to attach. - -``flags`` is of type ``enum hid_bpf_attach_flags``. +One can also set ``flags``, which is of type ``enum hid_bpf_attach_flags``. We can not rely on hidraw to bind a BPF program to a HID device. hidraw is an artefact of the processing of the HID device, and is not stable. Some drivers @@ -358,32 +363,15 @@ For that, we can create a basic skeleton for our BPF program:: extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz) __ksym; - extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 4096 * 64); } ringbuf SEC(".maps"); - struct attach_prog_args { - int prog_fd; - unsigned int hid; - unsigned int flags; - int retval; - }; - - SEC("syscall") - int attach_prog(struct attach_prog_args *ctx) - { - ctx->retval = hid_bpf_attach_prog(ctx->hid, - ctx->prog_fd, - ctx->flags); - return 0; - } - __u8 current_value = 0; - SEC("?fmod_ret/hid_bpf_device_event") + SEC("struct_ops/hid_device_event") int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx) { __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */); @@ -407,37 +395,37 @@ For that, we can create a basic skeleton for our BPF program:: return 0; } -To attach ``filter_switch``, userspace needs to call the ``attach_prog`` syscall -program first:: + SEC(".struct_ops.link") + struct hid_bpf_ops haptic_tablet = { + .hid_device_event = (void *)filter_switch, + }; + + +To attach ``haptic_tablet``, userspace needs to set ``hid_id`` first:: static int attach_filter(struct hid *hid_skel, int hid_id) { - int err, prog_fd; - int ret = -1; - struct attach_prog_args args = { - .hid = hid_id, - }; - DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, - .ctx_in = &args, - .ctx_size_in = sizeof(args), - ); + int err, link_fd; - args.prog_fd = bpf_program__fd(hid_skel->progs.filter_switch); + hid_skel->struct_ops.haptic_tablet->hid_id = hid_id; + err = hid__load(skel); + if (err) + return err; - prog_fd = bpf_program__fd(hid_skel->progs.attach_prog); + link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet); + if (!link_fd) { + fprintf(stderr, "can not attach HID-BPF program: %m\n"); + return -1; + } - err = bpf_prog_test_run_opts(prog_fd, &tattrs); - if (err) - return err; - - return args.retval; /* the fd of the created bpf_link */ + return link_fd; /* the fd of the created bpf_link */ } Our userspace program can now listen to notifications on the ring buffer, and is awaken only when the value changes. When the userspace program doesn't need to listen to events anymore, it can just -close the returned fd from :c:func:`attach_filter`, which will tell the kernel to +close the returned bpf link from :c:func:`attach_filter`, which will tell the kernel to detach the program from the HID device. Of course, in other use cases, the userspace program can also pin the fd to the diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 447b94aa99ab..1b4cc1b2c31d 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -20,11 +20,9 @@ struct hid_device; * struct hid_bpf_ctx - User accessible data for all HID programs * * ``data`` is not directly accessible from the context. We need to issue - * a call to ``hid_bpf_get_data()`` in order to get a pointer to that field. + * a call to hid_bpf_get_data() in order to get a pointer to that field. * - * All of these fields are currently read-only. - * - * @hid: the ``struct hid_device`` representing the device itself + * @hid: the &struct hid_device representing the device itself * @allocated_size: Allocated size of data. * * This is how much memory is available and can be requested @@ -41,6 +39,8 @@ struct hid_device; * ``size`` must always be less or equal than ``allocated_size`` (it is enforced * once all BPF programs have been run). * @retval: Return value of the previous program. + * + * ``hid`` and ``allocated_size`` are read-only, ``size`` and ``retval`` are read-write. */ struct hid_bpf_ctx { const struct hid_device *hid; From 5f42e19de53faf9e6d4455638f75b7c3a3f8d58f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:23 +0200 Subject: [PATCH 22/60] Documentation: HID: add a small blurb on udev-hid-bpf This is the current decision we took: we don't provide automatic loading of HID-BPF by the kernel directly, but rely on an external tool for it. This tool is currently udev-hid-bpf, so let's make people aware of it. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-11-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- Documentation/hid/hid-bpf.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst index 456e15097d87..8ae8f49801cb 100644 --- a/Documentation/hid/hid-bpf.rst +++ b/Documentation/hid/hid-bpf.rst @@ -129,6 +129,23 @@ When a BPF program needs to emit input events, it needs to talk with the HID protocol, and rely on the HID kernel processing to translate the HID data into input events. +In-tree HID-BPF programs and ``udev-hid-bpf`` +============================================= + +Official device fixes are shipped in the kernel tree as source in the +``drivers/hid/bpf/progs`` directory. This allows to add selftests to them in +``tools/testing/selftests/hid``. + +However, the compilation of these objects is not part of a regular kernel compilation +given that they need an external tool to be loaded. This tool is currently +`udev-hid-bpf `_. + +For convenience, that external repository duplicates the files from here in +``drivers/hid/bpf/progs`` into its own ``src/bpf/stable`` directory. This allows +distributions to not have to pull the entire kernel source tree to ship and package +those HID-BPF fixes. ``udev-hid-bpf`` also has capabilities of handling multiple +objects files depending on the kernel the user is running. + Available types of programs =========================== From 26ba1e0a982b9efe8b121d7e41dae4fdf118b048 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:24 +0200 Subject: [PATCH 23/60] HID: bpf: Artist24: remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit warning: unused variable ‘tilt’ [-Wunused-variable] Signed-off-by: Peter Hutterer Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-12-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/XPPen__Artist24.bpf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c index bc0b85c38445..d4d062c3a653 100644 --- a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c @@ -158,7 +158,6 @@ 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; - __u16 tilt; if (!data) return 0; /* EPERM check */ From c94ae2189acac38b01be60e3b878605fb328782c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:25 +0200 Subject: [PATCH 24/60] HID: bpf: error on warnings when compiling bpf objects There is no real reasons to paper over warnings for such small programs. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-13-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/bpf/progs/Makefile b/drivers/hid/bpf/progs/Makefile index 63ed7e02adf1..ec1fc642fd63 100644 --- a/drivers/hid/bpf/progs/Makefile +++ b/drivers/hid/bpf/progs/Makefile @@ -56,7 +56,7 @@ clean: %.bpf.o: %.bpf.c vmlinux.h $(BPFOBJ) | $(OUTPUT) $(call msg,BPF,$@) - $(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \ + $(Q)$(CLANG) -g -O2 --target=bpf -Wall -Werror $(INCLUDES) \ -c $(filter %.c,$^) -o $@ && \ $(LLVM_STRIP) -g $@ From bd0747543b3d973df6af0f43965f58965375d524 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:26 +0200 Subject: [PATCH 25/60] bpf: allow bpf helpers to be used into HID-BPF struct_ops Without this helpers like bpf_printk() or bpf_map_update() are not available, making anything but change of bytes impossible to do. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-14-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_struct_ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index dde547e734ed..1f24fadaa738 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -89,6 +89,7 @@ static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log, } 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, }; From f1a5fb6c7cf637e991cedc799e1470e01e148669 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:27 +0200 Subject: [PATCH 26/60] HID: bpf: rework hid_bpf_ops_btf_struct_access The idea is to provide a list of stucts and their editable fields. Currently no functional changes are introduced here, we will add some more writeable fields in the next patch. Acked-by: Alexei Starovoitov Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-15-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_struct_ops.c | 91 +++++++++++++++++++++------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index 1f24fadaa738..3ba46c3cd87b 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "hid_bpf_dispatch.h" @@ -52,40 +53,86 @@ static int hid_bpf_ops_check_member(const struct btf_type *t, return 0; } +struct hid_bpf_offset_write_range { + const char *struct_name; + u32 struct_length; + u32 start; + u32 end; +}; + static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log, const struct bpf_reg_state *reg, int off, int size) { - const struct btf_type *state; - const struct btf_type *t; - s32 type_id; +#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), \ + } - type_id = btf_find_by_name_kind(reg->btf, "hid_bpf_ctx", - BTF_KIND_STRUCT); - if (type_id < 0) - return -EINVAL; + const struct hid_bpf_offset_write_range write_ranges[] = { + WRITE_RANGE(hid_bpf_ctx, retval, false), + }; +#undef WRITE_RANGE + const struct btf_type *state = NULL; + const struct btf_type *t; + const char *cur = NULL; + int i; t = btf_type_by_id(reg->btf, reg->btf_id); - state = btf_type_by_id(reg->btf, type_id); - if (t != state) { - bpf_log(log, "only access to hid_bpf_ctx is supported\n"); - return -EACCES; + + 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; } - /* out-of-bound access in hid_bpf_ctx */ - if (off + size > sizeof(struct hid_bpf_ctx)) { - bpf_log(log, "write access at off %d with size %d\n", off, size); - return -EACCES; - } - if (off < offsetof(struct hid_bpf_ctx, retval)) { + 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 hid_bpf_ctx\n", - off, size); - return -EACCES; - } + "write access at off %d with size %d on read-only part of %s\n", + off, size, cur); - return NOT_INIT; + return -EACCES; } static const struct bpf_verifier_ops hid_bpf_verifier_ops = { From 33c0fb85b571b0f1bbdbf466e770eebeb29e6f41 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jun 2024 11:01:28 +0200 Subject: [PATCH 27/60] HID: bpf: make part of struct hid_device writable It is useful to change the name, the phys and/or the uniq of a struct hid_device during .rdesc_fixup(). For example, hid-uclogic.ko changes the uniq to store the firmware version to differentiate between 2 devices sharing the same PID. In the same way, changing the device name is useful when the device export 3 nodes, all with the same name. Link: https://lore.kernel.org/r/20240608-hid_bpf_struct_ops-v3-16-6ac6ade58329@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_struct_ops.c | 3 +++ include/linux/hid_bpf.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index 3ba46c3cd87b..5f200557ff12 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -74,6 +74,9 @@ static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log, 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; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 1b4cc1b2c31d..65d7e0acc8c2 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -43,7 +43,7 @@ struct hid_device; * ``hid`` and ``allocated_size`` are read-only, ``size`` and ``retval`` are read-write. */ struct hid_bpf_ctx { - const struct hid_device *hid; + struct hid_device *hid; __u32 allocated_size; union { __s32 retval; From f4ceb2a044f653344ea52c79d775fb876dfb1d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 14 Jun 2024 18:16:05 +0200 Subject: [PATCH 28/60] HID: uclogic: Avoid linking common code into multiple modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hid-uclogic-params.o and hid-uclogic-rdesc.o files are linked into both the driver module and the unit test, which triggers a W=1 warning: scripts/Makefile.build:236: drivers/hid/Makefile: hid-uclogic-rdesc.o is added to multiple modules: hid-uclogic hid-uclogic-test scripts/Makefile.build:236: drivers/hid/Makefile: hid-uclogic-params.o is added to multiple modules: hid-uclogic hid-uclogic-test Avoids this by moving these two files into a separate module that is used by the driver and the unit test. Reported-by: Arnd Bergmann Acked-by: Arnd Bergmann Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/Makefile | 6 ++---- drivers/hid/hid-uclogic-rdesc-test.c | 2 ++ drivers/hid/hid-uclogic-rdesc.c | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ce71b53ea6c5..e40f1ddebbb7 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -154,10 +154,8 @@ obj-$(CONFIG_HID_WINWING) += hid-winwing.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o -hid-uclogic-test-objs := hid-uclogic-rdesc.o \ - hid-uclogic-params.o \ - hid-uclogic-rdesc-test.o -obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-test.o +hid-uclogic-test-objs := hid-uclogic-rdesc-test.o +obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic.o hid-uclogic-test.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c index 90bf4e586e01..d6b18213f45f 100644 --- a/drivers/hid/hid-uclogic-rdesc-test.c +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -9,6 +9,8 @@ #include #include "./hid-uclogic-rdesc.h" +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); + struct uclogic_template_case { const char *name; const __u8 *template; diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index b6dfdf6356a6..6c7a90417569 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -17,6 +17,7 @@ #include "hid-uclogic-rdesc.h" #include #include +#include /* Fixed WP4030U report descriptor */ __u8 uclogic_rdesc_wp4030u_fixed_arr[] = { @@ -1242,3 +1243,4 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, return rdesc_ptr; } +EXPORT_SYMBOL_IF_KUNIT(uclogic_rdesc_template_apply); From 22c0a46a0d9731566ec05813f15dc22cf1096b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Fri, 14 Jun 2024 18:16:06 +0200 Subject: [PATCH 29/60] HID: uclogic: Add module description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not having it triggers a warning: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-uclogic.o Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index ad74cbc9a0aa..26bacbf1474e 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -568,6 +568,7 @@ module_hid_driver(uclogic_driver); MODULE_AUTHOR("Martin Rusko"); MODULE_AUTHOR("Nikolai Kondrashov"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("HID driver for UC-Logic devices not fully compliant with HID standard"); #ifdef CONFIG_HID_KUNIT_TEST #include "hid-uclogic-core-test.c" From 9e16bada9299d74fcce1f6b03606a08a2c16da81 Mon Sep 17 00:00:00 2001 From: Luis Felipe Hernandez Date: Tue, 25 Jun 2024 06:55:51 -0400 Subject: [PATCH 30/60] hid: bpf: Fix grammar * spelling fix: XBox -> Xbox, lowercase 'b' as per Microsoft branding * rephrase: paddle -> paddles, the controller itself has more than one paddle * rephrase: replace usage of "those" in favor of explicitly making reference to the paddles * grammatical fix: report -> reports, use present tense verb. * spelling fix: interpret * consistency: capitalize the first word in bullet points Signed-off-by: Luis Felipe Hernandez Link: https://patch.msgid.link/20240625105553.50830-1-luis.hernandez093@gmail.com [bentiss: renamed the file into Xbox, not XBox] Signed-off-by: Benjamin Tissoires --- ...lite-2.bpf.c => Microsoft__Xbox-Elite-2.bpf.c} | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) rename drivers/hid/bpf/progs/{Microsoft__XBox-Elite-2.bpf.c => Microsoft__Xbox-Elite-2.bpf.c} (91%) diff --git a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c b/drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c similarity index 91% rename from drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c rename to drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c index 70b16edfb59a..382bba735a2c 100644 --- a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c +++ b/drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c @@ -15,20 +15,19 @@ HID_BPF_CONFIG( ); /* - * When using the XBox Wireless Controller Elite 2 over Bluetooth, - * the device exports the paddle on the back of the device as a single + * 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 those usages properly and report KEY_UNKNOWN - * for it. + * The kernel doesn't process the paddles usage properly and reports KEY_UNKNOWN. * - * SDL doesn't know how to interprete that KEY_UNKNOWN and thus ignores the paddles. + * 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 interprete it properly: - * - we need an application collection of gamepad (so we have to close the current + * 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 + * - We need to change the usage to be buttons from 0x15 to 0x18 */ #define OFFSET_ASSIGN_SELECTION 211 From ebae0b2a6f4b3b949f30f076fbc65d3b0bb04785 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:22 +0200 Subject: [PATCH 31/60] HID: bpf: fix dispatch_hid_bpf_device_event uninitialized ret value Looks like if a bpf program gets inserted and then removed, hdev->bpf.device_data is then allocated, but the loop iterating over the bpf program is never assigning ret. This is a problem and also revealed another bug in which only the last value of ret was checked. This effectively meant than only the last program in the chain could change the size of the incoming buffer. Reported-by: Dan Carpenter Link: https://lore.kernel.org/all/00f7b624-219f-4a05-a7ad-5335f15a41c7@moroto.mountain Fixes: 4a86220e046d ("HID: bpf: remove tracing HID-BPF capability") Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-1-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 06cc628e7bb4..b7b11a7c69db 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -57,11 +57,12 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type } if (ret) - ctx_kern.ctx.retval = 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); From 67eccf151d76a9939ad8a50c6db5cb486b01df24 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:23 +0200 Subject: [PATCH 32/60] HID: add source argument to HID low level functions This allows to know who actually sent what when we process the request to the device. This will be useful for a BPF firewall program to allow or not requests coming from a dedicated hidraw node client. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-2-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 12 ++-- drivers/hid/bpf/hid_bpf_struct_ops.c | 2 +- drivers/hid/hid-core.c | 95 +++++++++++++++++----------- drivers/hid/hidraw.c | 10 +-- include/linux/hid.h | 6 ++ include/linux/hid_bpf.h | 16 +++-- 6 files changed, 87 insertions(+), 54 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index b7b11a7c69db..2df31decaac3 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL(hid_ops); u8 * dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data, - u32 *size, int interrupt) + u32 *size, int interrupt, u64 source) { struct hid_bpf_ctx_kern ctx_kern = { .ctx = { @@ -50,7 +50,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type 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); + ret = e->hid_device_event(&ctx_kern.ctx, type, source); if (ret < 0) { rcu_read_unlock(); return ERR_PTR(ret); @@ -359,7 +359,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, dma_data, size, rtype, - reqtype); + reqtype, + (__u64)ctx); if (ret > 0) memcpy(buf, dma_data, ret); @@ -398,7 +399,8 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) ret = hid_ops->hid_hw_output_report(hdev, dma_data, - size); + size, + (__u64)ctx); kfree(dma_data); return ret; @@ -429,7 +431,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf hdev = (struct hid_device *)ctx->hid; /* discard const */ - return hid_ops->hid_input_report(hdev, type, buf, size, 0); + return hid_ops->hid_input_report(hdev, type, buf, size, 0, (__u64)ctx); } __bpf_kfunc_end_defs(); diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index 5f200557ff12..8063db1c8d62 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -257,7 +257,7 @@ static void hid_bpf_unreg(void *kdata) hid_put_device(hdev); } -static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type) +static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type, __u64 source) { return 0; } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aed8850a4d01..0775a32f5272 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2025,19 +2025,9 @@ out: } EXPORT_SYMBOL_GPL(hid_report_raw_event); -/** - * hid_input_report - report data from lower layer (usb, bt...) - * - * @hid: hid device - * @type: HID report type (HID_*_REPORT) - * @data: report contents - * @size: size of data parameter - * @interrupt: distinguish between interrupt and control transfers - * - * This is data entry for lower layers. - */ -int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, - int interrupt) + +static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, + u8 *data, u32 size, int interrupt, u64 source) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; @@ -2057,7 +2047,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data report_enum = hid->report_enum + type; hdrv = hid->driver; - data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt); + data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source); if (IS_ERR(data)) { ret = PTR_ERR(data); goto unlock; @@ -2092,6 +2082,23 @@ unlock: up(&hid->driver_input_lock); return ret; } + +/** + * hid_input_report - report data from lower layer (usb, bt...) + * + * @hid: hid device + * @type: HID report type (HID_*_REPORT) + * @data: report contents + * @size: size of data parameter + * @interrupt: distinguish between interrupt and control transfers + * + * This is data entry for lower layers. + */ +int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, + int interrupt) +{ + return __hid_input_report(hid, type, data, size, interrupt, 0); +} EXPORT_SYMBOL_GPL(hid_input_report); bool hid_match_one_id(const struct hid_device *hdev, @@ -2392,6 +2399,24 @@ void hid_hw_request(struct hid_device *hdev, } EXPORT_SYMBOL_GPL(hid_hw_request); +int __hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, enum hid_report_type rtype, + enum hid_class_request reqtype, + __u64 source) +{ + unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; + + if (hdev->ll_driver->max_buffer_size) + max_buffer_size = hdev->ll_driver->max_buffer_size; + + if (len < 1 || len > max_buffer_size || !buf) + return -EINVAL; + + return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, + rtype, reqtype); +} + /** * hid_hw_raw_request - send report request to device * @@ -2410,29 +2435,11 @@ int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype) { - unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; - - if (hdev->ll_driver->max_buffer_size) - max_buffer_size = hdev->ll_driver->max_buffer_size; - - if (len < 1 || len > max_buffer_size || !buf) - return -EINVAL; - - return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, - rtype, reqtype); + return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0); } EXPORT_SYMBOL_GPL(hid_hw_raw_request); -/** - * hid_hw_output_report - send output report to device - * - * @hdev: hid device - * @buf: raw data to transfer - * @len: length of buf - * - * Return: count of data transferred, negative if error - */ -int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) +int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; @@ -2447,6 +2454,20 @@ int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) return -ENOSYS; } + +/** + * hid_hw_output_report - send output report to device + * + * @hdev: hid device + * @buf: raw data to transfer + * @len: length of buf + * + * Return: count of data transferred, negative if error + */ +int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) +{ + return __hid_hw_output_report(hdev, buf, len, 0); +} EXPORT_SYMBOL_GPL(hid_hw_output_report); #ifdef CONFIG_PM @@ -2972,9 +2993,9 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed); #ifdef CONFIG_HID_BPF static struct hid_ops __hid_ops = { .hid_get_report = hid_get_report, - .hid_hw_raw_request = hid_hw_raw_request, - .hid_hw_output_report = hid_hw_output_report, - .hid_input_report = hid_input_report, + .hid_hw_raw_request = __hid_hw_raw_request, + .hid_hw_output_report = __hid_hw_output_report, + .hid_input_report = __hid_input_report, .owner = THIS_MODULE, .bus_type = &hid_bus_type, }; diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 2bc762d31ac7..6d2a6d38e42a 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, if ((report_type == HID_OUTPUT_REPORT) && !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) { - ret = hid_hw_output_report(dev, buf, count); + ret = __hid_hw_output_report(dev, buf, count, (__u64)file); /* * compatibility with old implementation of USB-HID and I2C-HID: * if the device does not support receiving output reports, @@ -150,8 +150,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, goto out_free; } - ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type, - HID_REQ_SET_REPORT); + ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type, + HID_REQ_SET_REPORT, (__u64)file); out_free: kfree(buf); @@ -227,8 +227,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t goto out_free; } - ret = hid_hw_raw_request(dev, report_number, buf, count, report_type, - HID_REQ_GET_REPORT); + ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type, + HID_REQ_GET_REPORT, (__u64)file); if (ret < 0) goto out_free; diff --git a/include/linux/hid.h b/include/linux/hid.h index 8e06d89698e6..dac2804b4562 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1125,6 +1125,12 @@ int __must_check hid_hw_open(struct hid_device *hdev); void hid_hw_close(struct hid_device *hdev); void hid_hw_request(struct hid_device *hdev, struct hid_report *report, enum hid_class_request reqtype); +int __hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, enum hid_report_type rtype, + enum hid_class_request reqtype, + __u64 source); +int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source); int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 65d7e0acc8c2..a54741db0415 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -66,10 +66,12 @@ struct hid_ops { int (*hid_hw_raw_request)(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, - enum hid_class_request reqtype); - int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len); + enum hid_class_request reqtype, + __u64 source); + int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, + __u64 source); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt); + u8 *data, u32 size, int interrupt, u64 source); struct module *owner; const struct bus_type *bus_type; }; @@ -110,7 +112,8 @@ struct hid_bpf_ops { * * Context: Interrupt context. */ - int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type); + int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, + __u64 source); /** * @hid_rdesc_fixup: called when the probe function parses the report descriptor @@ -146,7 +149,7 @@ struct hid_bpf { #ifdef CONFIG_HID_BPF u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, - u32 *size, int interrupt); + u32 *size, int interrupt, u64 source); int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); @@ -154,7 +157,8 @@ void hid_bpf_device_init(struct hid_device *hid); u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size); #else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 *size, int interrupt) { return data; } + u8 *data, u32 *size, int interrupt, + u64 source) { return data; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} From 6cd735f0e57a6c8510ad92f5b63837a8d0cff3a7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:24 +0200 Subject: [PATCH 33/60] HID: bpf: protect HID-BPF prog_list access by a SRCU We want to add sleepable callbacks for hid_hw_raw_request() and hid_hw_output_report(), but we can not use a plain RCU for those. Prepare for a SRCU so we can extend HID-BPF. This changes a little bit how hid_bpf_device_init() behaves, as it may now fail, so there is a tiny hid-core.c change to accommodate for this. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-3-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 6 +++++- drivers/hid/bpf/hid_bpf_struct_ops.c | 2 ++ drivers/hid/hid-core.c | 8 +++++++- include/linux/hid_bpf.h | 6 ++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 2df31decaac3..c026248e3d73 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -506,13 +506,17 @@ void hid_bpf_destroy_device(struct hid_device *hdev) 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); -void hid_bpf_device_init(struct hid_device *hdev) +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); diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index 8063db1c8d62..d34731a1b457 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -214,6 +214,7 @@ static int hid_bpf_reg(void *kdata) 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); @@ -244,6 +245,7 @@ static void hid_bpf_unreg(void *kdata) mutex_lock(&hdev->bpf.prog_list_lock); list_del_rcu(&ops->list); + synchronize_srcu(&hdev->bpf.srcu); reconnect = hdev->bpf.rdesc_ops == ops; if (reconnect) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 0775a32f5272..ad08289752da 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2875,9 +2875,15 @@ struct hid_device *hid_allocate_device(void) mutex_init(&hdev->ll_open_lock); kref_init(&hdev->ref); - hid_bpf_device_init(hdev); + ret = hid_bpf_device_init(hdev); + if (ret) + goto out_err; return hdev; + +out_err: + hid_destroy_device(hdev); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(hid_allocate_device); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index a54741db0415..f93845de5cac 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -5,6 +5,7 @@ #include #include +#include #include struct hid_device; @@ -145,6 +146,7 @@ struct hid_bpf { struct hid_bpf_ops *rdesc_ops; struct list_head prog_list; struct mutex prog_list_lock; /* protects prog_list update */ + struct srcu_struct srcu; /* protects prog_list read-only access */ }; #ifdef CONFIG_HID_BPF @@ -153,7 +155,7 @@ u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type t int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); -void hid_bpf_device_init(struct hid_device *hid); +int hid_bpf_device_init(struct hid_device *hid); u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size); #else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, @@ -162,7 +164,7 @@ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} -static inline void hid_bpf_device_init(struct hid_device *hid) {} +static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; } #define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \ ((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL)) From 8bd0488b5ea58655ad6fdcbe0408ef49b16882b1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:25 +0200 Subject: [PATCH 34/60] HID: bpf: add HID-BPF hooks for hid_hw_raw_requests This allows to intercept and prevent or change the behavior of hid_hw_raw_request() from a bpf program. The intent is to solve a couple of use case: - firewalling a HID device: a firewall can monitor who opens the hidraw nodes and then prevent or allow access to write operations on that hidraw node. - change the behavior of a device and emulate a new HID feature request The hook is allowed to be run as sleepable so it can itself call hid_bpf_hw_request(), which allows to "convert" one feature request into another or even call the feature request on a different HID device on the same physical device. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-4-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 38 ++++++++++++++++++++++++++++ drivers/hid/bpf/hid_bpf_struct_ops.c | 1 + drivers/hid/hid-core.c | 6 +++++ include/linux/hid_bpf.h | 35 +++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index c026248e3d73..37a1bb381684 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -74,6 +74,44 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type } 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) +{ + struct hid_bpf_ctx_kern ctx_kern = { + .ctx = { + .hid = hdev, + .allocated_size = size, + .size = size, + }, + .data = buf, + }; + struct hid_bpf_ops *e; + int ret, idx; + + 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); + u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size) { int ret; diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index d34731a1b457..a540a4417174 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -44,6 +44,7 @@ static int hid_bpf_ops_check_member(const struct btf_type *t, switch (moff) { case offsetof(struct hid_bpf_ops, hid_rdesc_fixup): + case offsetof(struct hid_bpf_ops, hid_hw_request): break; default: if (prog->sleepable) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ad08289752da..16731804c6bd 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2406,6 +2406,7 @@ int __hid_hw_raw_request(struct hid_device *hdev, __u64 source) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; + int ret; if (hdev->ll_driver->max_buffer_size) max_buffer_size = hdev->ll_driver->max_buffer_size; @@ -2413,6 +2414,11 @@ int __hid_hw_raw_request(struct hid_device *hdev, if (len < 1 || len > max_buffer_size || !buf) return -EINVAL; + ret = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, len, rtype, + reqtype, source); + if (ret) + return ret; + return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, rtype, reqtype); } diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index f93845de5cac..3c01f7f8b6fc 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -130,6 +130,31 @@ struct hid_bpf_ops { */ int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); + /** + * @hid_hw_request: called whenever a hid_hw_raw_request() call is emitted + * on the HID device + * + * It has the following arguments: + * + * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * ``reportnum``: the report number, as in hid_hw_raw_request() + * ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, + * ``HID_OUTPUT_REPORT``) + * ``reqtype``: the request + * ``source``: a u64 referring to a uniq but identifiable source. If %0, the + * kernel itself emitted that call. For hidraw, ``source`` is set + * to the associated ``struct file *``. + * + * Return: %0 to keep processing the request by hid-core; any other value + * stops hid-core from processing that event. A positive value should be + * returned with the number of bytes returned in the incoming buffer; a + * negative error code interrupts the processing of this call. + */ + int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, + __u64 source); + + /* private: do not show up in the docs */ struct hid_device *hdev; }; @@ -152,6 +177,11 @@ struct hid_bpf { #ifdef CONFIG_HID_BPF u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 *size, int interrupt, u64 source); +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); int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); @@ -161,6 +191,11 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 *size, int interrupt, u64 source) { return data; } +static inline 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) { return 0; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} From 75839101ce52e319cb2154a027d14f1f0aa3be09 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:26 +0200 Subject: [PATCH 35/60] HID: bpf: prevent infinite recursions with hid_hw_raw_requests hooks When we attach a sleepable hook to hid_hw_raw_requests, we can (and in many cases should) call ourself hid_bpf_raw_request(), to actually fetch data from the device itself. However, this means that we might enter an infinite loop between hid_hw_raw_requests hooks and hid_bpf_hw_request() call. To prevent that, if a hid_bpf_hw_request() call is emitted, we prevent any new call of this kfunc by storing the information in the context. This way we can always trace/monitor/filter the incoming bpf requests, while preventing those loops to happen. I don't think exposing "from_bpf" is very interesting because while writing such a bpf program, you need to match at least the report number and/or the source of the call. So a blind "if there is a hid_hw_raw_request() call, I'm emitting another one" makes no real sense. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-5-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 12 ++++++++++-- drivers/hid/bpf/hid_bpf_dispatch.h | 1 + drivers/hid/hid-core.c | 6 +++--- drivers/hid/hidraw.c | 4 ++-- include/linux/hid.h | 2 +- include/linux/hid_bpf.h | 6 +++--- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 37a1bb381684..61c02538e591 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -78,7 +78,7 @@ 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) + u64 source, bool from_bpf) { struct hid_bpf_ctx_kern ctx_kern = { .ctx = { @@ -87,6 +87,7 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, .size = size, }, .data = buf, + .from_bpf = from_bpf, }; struct hid_bpf_ops *e; int ret, idx; @@ -364,11 +365,17 @@ __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; struct hid_device *hdev; 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); if (ret) @@ -398,7 +405,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, size, rtype, reqtype, - (__u64)ctx); + (__u64)ctx, + true); /* prevent infinite recursions */ if (ret > 0) memcpy(buf, dma_data, ret); diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h index 835e6f69f479..44c6ea22233f 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.h +++ b/drivers/hid/bpf/hid_bpf_dispatch.h @@ -8,6 +8,7 @@ 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); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 16731804c6bd..2038ba08eaa1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2403,7 +2403,7 @@ int __hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source) + __u64 source, bool from_bpf) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; int ret; @@ -2415,7 +2415,7 @@ int __hid_hw_raw_request(struct hid_device *hdev, return -EINVAL; ret = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, len, rtype, - reqtype, source); + reqtype, source, from_bpf); if (ret) return ret; @@ -2441,7 +2441,7 @@ int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype) { - return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0); + return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0, false); } EXPORT_SYMBOL_GPL(hid_hw_raw_request); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 6d2a6d38e42a..4ba3131de614 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -151,7 +151,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, } ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type, - HID_REQ_SET_REPORT, (__u64)file); + HID_REQ_SET_REPORT, (__u64)file, false); out_free: kfree(buf); @@ -228,7 +228,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t } ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type, - HID_REQ_GET_REPORT, (__u64)file); + HID_REQ_GET_REPORT, (__u64)file, false); if (ret < 0) goto out_free; diff --git a/include/linux/hid.h b/include/linux/hid.h index dac2804b4562..24d0d7c0bd33 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1129,7 +1129,7 @@ int __hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source); + __u64 source, bool from_bpf); int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source); int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 3c01f7f8b6fc..088c94b6d8ec 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -68,7 +68,7 @@ struct hid_ops { unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source); + __u64 source, bool from_bpf); int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, @@ -181,7 +181,7 @@ 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); + __u64 source, bool from_bpf); int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); @@ -195,7 +195,7 @@ static inline 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) { return 0; } + u64 source, bool from_bpf) { return 0; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} From 015a4a2a439b285943da471d38b2721bbe4d8b39 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:27 +0200 Subject: [PATCH 36/60] selftests/hid: add tests for hid_hw_raw_request HID-BPF hooks We add 3 new tests: - first, we make sure we can prevent the raw_request to happen - second, we make sure that we can detect that a given hidraw client was actually doing the request, and for that client only, call ourself hid_bpf_hw_request(), returning a custom value - last, we ensure that we can not loop between hooks for hid_hw_raw_request() and manual calls to hid_bpf_hw_request() from that hook Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-6-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 109 ++++++++++++++++++++++++ tools/testing/selftests/hid/progs/hid.c | 79 +++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index 45e173db35bd..f97d56337d8a 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -470,6 +470,11 @@ static void detach_bpf(FIXTURE_DATA(hid_bpf) * self) close(self->hidraw_fd); self->hidraw_fd = 0; + if (!self->skel) + return; + + hid__detach(self->skel); + for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) { if (self->hid_links[i]) bpf_link__destroy(self->hid_links[i]); @@ -575,6 +580,8 @@ static void load_programs(const struct test_program programs[], programs[i].name + 4); } + hid__attach(self->skel); + self->hidraw_fd = open_hidraw(self->dev_id); ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); } @@ -919,6 +926,108 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call) ASSERT_EQ(args.data[1], 2); } +/* + * Call hid_hw_raw_request against the given uhid device, + * check that the program is called and prevents the + * call to uhid. + */ +TEST_F(hid_bpf, test_hid_filter_raw_request_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_filter_raw_request" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* first check that we did not attach to device_event */ + + /* inject one event */ + buf[0] = 1; + buf[1] = 42; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[1], 42); + ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test"); + + /* now check that our program is preventing hid_hw_raw_request() */ + + /* emit hid_hw_raw_request from hidraw */ + /* Get Feature */ + memset(buf, 0, sizeof(buf)); + buf[0] = 0x1; /* Report Number */ + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err); + ASSERT_EQ(errno, 20) TH_LOG("unexpected error code while reading HIDIOCGFEATURE: %d", + errno); + + /* remove our bpf program and check that we can now emit commands */ + + /* detach the program */ + detach_bpf(self); + + self->hidraw_fd = open_hidraw(self->dev_id); + ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); + + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err); +} + +/* + * Call hid_hw_raw_request against the given uhid device, + * check that the program is called and can issue the call + * to uhid and transform the answer. + */ +TEST_F(hid_bpf, test_hid_change_raw_request_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_hidraw_raw_request" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* emit hid_hw_raw_request from hidraw */ + /* Get Feature */ + memset(buf, 0, sizeof(buf)); + buf[0] = 0x1; /* Report Number */ + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err); + + ASSERT_EQ(buf[0], 2); + ASSERT_EQ(buf[1], 3); + ASSERT_EQ(buf[2], 4); +} + +/* + * Call hid_hw_raw_request against the given uhid device, + * check that the program is not making infinite loops. + */ +TEST_F(hid_bpf, test_hid_infinite_loop_raw_request_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_infinite_loop_raw_request" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* emit hid_hw_raw_request from hidraw */ + /* Get Feature */ + memset(buf, 0, sizeof(buf)); + buf[0] = 0x1; /* Report Number */ + err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); + ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err); +} + /* * Attach hid_insert{0,1,2} to the given uhid device, * retrieve and open the matching hidraw node, diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index 2e7e5a736dc6..0ad452fcca58 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -306,3 +306,82 @@ SEC(".struct_ops.link") struct hid_bpf_ops test_insert3 = { .hid_device_event = (void *)hid_test_insert3, }; + +SEC("?struct_ops/hid_hw_request") +int BPF_PROG(hid_test_filter_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source) +{ + return -20; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_filter_raw_request = { + .hid_hw_request = (void *)hid_test_filter_raw_request, +}; + +static struct file *current_file; + +SEC("fentry/hidraw_open") +int BPF_PROG(hidraw_open, struct inode *inode, struct file *file) +{ + current_file = file; + return 0; +} + +SEC("?struct_ops.s/hid_hw_request") +int BPF_PROG(hid_test_hidraw_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */); + int ret; + + if (!data) + return 0; /* EPERM check */ + + /* check if the incoming request comes from our hidraw operation */ + if (source == (__u64)current_file) { + data[0] = reportnum; + + ret = hid_bpf_hw_request(hctx, data, 2, rtype, reqtype); + if (ret != 2) + return -1; + data[0] = reportnum + 1; + data[1] = reportnum + 2; + data[2] = reportnum + 3; + return 3; + } + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_hidraw_raw_request = { + .hid_hw_request = (void *)hid_test_hidraw_raw_request, +}; + +SEC("?struct_ops.s/hid_hw_request") +int BPF_PROG(hid_test_infinite_loop_raw_request, struct hid_bpf_ctx *hctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */); + int ret; + + if (!data) + return 0; /* EPERM check */ + + /* always forward the request as-is to the device, hid-bpf should prevent + * infinite loops. + */ + data[0] = reportnum; + + ret = hid_bpf_hw_request(hctx, data, 2, rtype, reqtype); + if (ret == 2) + return 3; + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_infinite_loop_raw_request = { + .hid_hw_request = (void *)hid_test_infinite_loop_raw_request, +}; From 9286675a2aed40a517be8cc4e283a04f473275b5 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:28 +0200 Subject: [PATCH 37/60] HID: bpf: add HID-BPF hooks for hid_hw_output_report Same story than hid_hw_raw_requests: This allows to intercept and prevent or change the behavior of hid_hw_output_report() from a bpf program. The intent is to solve a couple of use case: - firewalling a HID device: a firewall can monitor who opens the hidraw nodes and then prevent or allow access to write operations on that hidraw node. - change the behavior of a device and emulate a new HID feature request The hook is allowed to be run as sleepable so it can itself call hid_hw_output_report(), which allows to "convert" one feature request into another or even call the feature request on a different HID device on the same physical device. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-7-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 39 +++++++++++++++++++++++++--- drivers/hid/bpf/hid_bpf_struct_ops.c | 1 + drivers/hid/hid-core.c | 10 +++++-- drivers/hid/hidraw.c | 2 +- include/linux/hid.h | 3 ++- include/linux/hid_bpf.h | 24 ++++++++++++++++- 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 61c02538e591..fb12b399fc25 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -113,6 +113,40 @@ out: } 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; + + 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); + u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size) { int ret; @@ -443,10 +477,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) if (!dma_data) return -ENOMEM; - ret = hid_ops->hid_hw_output_report(hdev, - dma_data, - size, - (__u64)ctx); + ret = hid_ops->hid_hw_output_report(hdev, dma_data, size, (__u64)ctx, true); kfree(dma_data); return ret; diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index a540a4417174..37d2f8e2413a 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -45,6 +45,7 @@ static int hid_bpf_ops_check_member(const struct btf_type *t, 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) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2038ba08eaa1..bb6f334f05bd 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2445,9 +2445,11 @@ int hid_hw_raw_request(struct hid_device *hdev, } EXPORT_SYMBOL_GPL(hid_hw_raw_request); -int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source) +int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source, + bool from_bpf) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; + int ret; if (hdev->ll_driver->max_buffer_size) max_buffer_size = hdev->ll_driver->max_buffer_size; @@ -2455,6 +2457,10 @@ int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 if (len < 1 || len > max_buffer_size || !buf) return -EINVAL; + ret = dispatch_hid_bpf_output_report(hdev, buf, len, source, from_bpf); + if (ret) + return ret; + if (hdev->ll_driver->output_report) return hdev->ll_driver->output_report(hdev, buf, len); @@ -2472,7 +2478,7 @@ int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 */ int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) { - return __hid_hw_output_report(hdev, buf, len, 0); + return __hid_hw_output_report(hdev, buf, len, 0, false); } EXPORT_SYMBOL_GPL(hid_hw_output_report); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 4ba3131de614..c2396916cdaa 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, if ((report_type == HID_OUTPUT_REPORT) && !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) { - ret = __hid_hw_output_report(dev, buf, count, (__u64)file); + ret = __hid_hw_output_report(dev, buf, count, (__u64)file, false); /* * compatibility with old implementation of USB-HID and I2C-HID: * if the device does not support receiving output reports, diff --git a/include/linux/hid.h b/include/linux/hid.h index 24d0d7c0bd33..1533c9dcd3a6 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1130,7 +1130,8 @@ int __hid_hw_raw_request(struct hid_device *hdev, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source, bool from_bpf); -int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source); +int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source, + bool from_bpf); int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 088c94b6d8ec..f35508a73067 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -70,7 +70,7 @@ struct hid_ops { enum hid_class_request reqtype, __u64 source, bool from_bpf); int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, - __u64 source); + __u64 source, bool from_bpf); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, int interrupt, u64 source); struct module *owner; @@ -154,6 +154,24 @@ struct hid_bpf_ops { enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source); + /** + * @hid_hw_output_report: called whenever a hid_hw_output_report() call is emitted + * on the HID device + * + * It has the following arguments: + * + * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * ``source``: a u64 referring to a uniq but identifiable source. If %0, the + * kernel itself emitted that call. For hidraw, ``source`` is set + * to the associated ``struct file *``. + * + * Return: %0 to keep processing the request by hid-core; any other value + * stops hid-core from processing that event. A positive value should be + * returned with the number of bytes written to the device; a negative error + * code interrupts the processing of this call. + */ + int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, __u64 source); + /* private: do not show up in the docs */ struct hid_device *hdev; @@ -182,6 +200,8 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, u32 size, enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source, bool from_bpf); +int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size, + __u64 source, bool from_bpf); int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); @@ -196,6 +216,8 @@ static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, u32 size, enum hid_report_type rtype, enum hid_class_request reqtype, u64 source, bool from_bpf) { return 0; } +static inline int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size, + __u64 source, bool from_bpf) { return 0; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} From 3ac83fcd6e67c86d25040e6818972f2c36b51d23 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:29 +0200 Subject: [PATCH 38/60] selftests/hid: add tests for hid_hw_output_report HID-BPF hooks We add 3 new tests: - first, we make sure we can prevent the output_report to happen - second, we make sure that we can detect that a given hidraw client was actually doing the request, and for that client only, call ourself hid_bpf_hw_output_report(), returning a custom value - last, we ensure that we can not loop between hooks for hid_hw_output_report() and manual calls to hid_bpf_hw_output_report() from that same hook Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-8-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 5 ++ tools/testing/selftests/hid/hid_bpf.c | 102 ++++++++++++++++++++++++ tools/testing/selftests/hid/progs/hid.c | 58 ++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index fb12b399fc25..68a9a2fcbc06 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -461,11 +461,16 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, __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; struct hid_device *hdev; 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); if (ret) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index f97d56337d8a..40aedd1d9dc5 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -1028,6 +1028,108 @@ TEST_F(hid_bpf, test_hid_infinite_loop_raw_request_call) ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err); } +/* + * Call hid_hw_output_report against the given uhid device, + * check that the program is called and prevents the + * call to uhid. + */ +TEST_F(hid_bpf, test_hid_filter_output_report_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_filter_output_report" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* first check that we did not attach to device_event */ + + /* inject one event */ + buf[0] = 1; + buf[1] = 42; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[1], 42); + ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test"); + + /* now check that our program is preventing hid_hw_output_report() */ + + buf[0] = 1; /* report ID */ + buf[1] = 2; + buf[2] = 42; + + err = write(self->hidraw_fd, buf, 3); + ASSERT_LT(err, 0) TH_LOG("unexpected success while sending hid_hw_output_report: %d", err); + ASSERT_EQ(errno, 25) TH_LOG("unexpected error code while sending hid_hw_output_report: %d", + errno); + + /* remove our bpf program and check that we can now emit commands */ + + /* detach the program */ + detach_bpf(self); + + self->hidraw_fd = open_hidraw(self->dev_id); + ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); + + err = write(self->hidraw_fd, buf, 3); + ASSERT_GE(err, 0) TH_LOG("error while sending hid_hw_output_report: %d", err); +} + +/* + * Call hid_hw_output_report against the given uhid device, + * check that the program is called and can issue the call + * to uhid and transform the answer. + */ +TEST_F(hid_bpf, test_hid_change_output_report_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_hidraw_output_report" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* emit hid_hw_output_report from hidraw */ + buf[0] = 1; /* report ID */ + buf[1] = 2; + buf[2] = 42; + + err = write(self->hidraw_fd, buf, 10); + ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d", + err); +} + +/* + * Call hid_hw_output_report against the given uhid device, + * check that the program is not making infinite loops. + */ +TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_infinite_loop_output_report" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* emit hid_hw_output_report from hidraw */ + buf[0] = 1; /* report ID */ + buf[1] = 2; + buf[2] = 42; + + err = write(self->hidraw_fd, buf, 8); + ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d", + err); +} + /* * Attach hid_insert{0,1,2} to the given uhid device, * retrieve and open the matching hidraw node, diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index 0ad452fcca58..1fa288b76cd5 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -385,3 +385,61 @@ SEC(".struct_ops.link") struct hid_bpf_ops test_infinite_loop_raw_request = { .hid_hw_request = (void *)hid_test_infinite_loop_raw_request, }; + +SEC("?struct_ops/hid_hw_output_report") +int BPF_PROG(hid_test_filter_output_report, struct hid_bpf_ctx *hctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, __u64 source) +{ + return -25; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_filter_output_report = { + .hid_hw_output_report = (void *)hid_test_filter_output_report, +}; + +SEC("?struct_ops.s/hid_hw_output_report") +int BPF_PROG(hid_test_hidraw_output_report, struct hid_bpf_ctx *hctx, __u64 source) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */); + int ret; + + if (!data) + return 0; /* EPERM check */ + + /* check if the incoming request comes from our hidraw operation */ + if (source == (__u64)current_file) + return hid_bpf_hw_output_report(hctx, data, 2); + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_hidraw_output_report = { + .hid_hw_output_report = (void *)hid_test_hidraw_output_report, +}; + +SEC("?struct_ops.s/hid_hw_output_report") +int BPF_PROG(hid_test_infinite_loop_output_report, struct hid_bpf_ctx *hctx, __u64 source) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 3 /* size */); + int ret; + + if (!data) + return 0; /* EPERM check */ + + /* always forward the request as-is to the device, hid-bpf should prevent + * infinite loops. + */ + + ret = hid_bpf_hw_output_report(hctx, data, 2); + if (ret == 2) + return 2; + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_infinite_loop_output_report = { + .hid_hw_output_report = (void *)hid_test_infinite_loop_output_report, +}; From fa03f398a8ac46f46927e0b509b302ebe0ed7e8a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:30 +0200 Subject: [PATCH 39/60] HID: bpf: make hid_bpf_input_report() sleep until the device is ready hid_bpf_input_report() is already marked to be used in sleepable context only. So instead of hammering with timers the device to hopefully get an available slot where the device is not sending events, we can make that kfunc wait for the current event to be terminated before it goes in. This allows to work with the following pseudo code: in struct_ops/hid_device_event: - schedule a bpf_wq, which calls hid_bpf_input_report() - once this struct_ops function terminates, hid_bpf_input_report() immediately starts before the next event Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-9-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 16 ++++++++++++---- drivers/hid/hid-core.c | 16 ++++++++++++---- include/linux/hid_bpf.h | 3 ++- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 68a9a2fcbc06..5174dc6d9d18 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -496,24 +496,32 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) * @buf: a %PTR_TO_MEM buffer * @buf__sz: the size of the data to transfer * - * Returns %0 on success, a negative error code otherwise. + * 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) { - struct hid_device *hdev; size_t size = buf__sz; int ret; + ret = down_interruptible(&ctx->hid->driver_input_lock); + if (ret) + return ret; + /* check arguments */ ret = __hid_bpf_hw_check_params(ctx, buf, &size, type); if (ret) return ret; - hdev = (struct hid_device *)ctx->hid; /* discard const */ + ret = hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (__u64)ctx, + true /* lock_already_taken */); - return hid_ops->hid_input_report(hdev, type, buf, size, 0, (__u64)ctx); + up(&ctx->hid->driver_input_lock); + + return ret; } __bpf_kfunc_end_defs(); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bb6f334f05bd..e9b5f44683fd 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2027,7 +2027,8 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt, u64 source) + u8 *data, u32 size, int interrupt, u64 source, + bool lock_already_taken) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; @@ -2037,8 +2038,13 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, if (!hid) return -ENODEV; - if (down_trylock(&hid->driver_input_lock)) + ret = down_trylock(&hid->driver_input_lock); + if (lock_already_taken && !ret) { + up(&hid->driver_input_lock); + return -EINVAL; + } else if (!lock_already_taken && ret) { return -EBUSY; + } if (!hid->driver) { ret = -ENODEV; @@ -2079,7 +2085,8 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, ret = hid_report_raw_event(hid, type, data, size, interrupt); unlock: - up(&hid->driver_input_lock); + if (!lock_already_taken) + up(&hid->driver_input_lock); return ret; } @@ -2097,7 +2104,8 @@ unlock: int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, int interrupt) { - return __hid_input_report(hid, type, data, size, interrupt, 0); + return __hid_input_report(hid, type, data, size, interrupt, 0, + false /* lock_already_taken */); } EXPORT_SYMBOL_GPL(hid_input_report); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index f35508a73067..7f04353d09e9 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -72,7 +72,8 @@ struct hid_ops { int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source, bool from_bpf); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt, u64 source); + u8 *data, u32 size, int interrupt, u64 source, + bool lock_already_taken); struct module *owner; const struct bus_type *bus_type; }; From fe8d561db3e82a1130c59ebc143d557b0bdb0cff Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:31 +0200 Subject: [PATCH 40/60] selftests/hid: add wq test for hid_bpf_input_report() Now that bpf_wq is available, we can write a test with it. Having hid_bpf_input_report() waiting for the device means that we can directly call it, and we get that event when the device is ready. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-10-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 38 +++++++++ tools/testing/selftests/hid/progs/hid.c | 79 +++++++++++++++++++ .../selftests/hid/progs/hid_bpf_helpers.h | 9 +++ 3 files changed, 126 insertions(+) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index 40aedd1d9dc5..31637b3b8db5 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -1130,6 +1130,44 @@ TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call) err); } +/* + * Attach hid_multiply_event_wq to the given uhid device, + * retrieve and open the matching hidraw node, + * inject one event in the uhid device, + * check that the program sees it and can add extra data + */ +TEST_F(hid_bpf, test_multiply_events_wq) +{ + const struct test_program progs[] = { + { .name = "hid_test_multiply_events_wq" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* inject one event */ + buf[0] = 1; + buf[1] = 42; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[1], 47); + + usleep(100000); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 2); + ASSERT_EQ(buf[1], 3); +} + /* * Attach hid_insert{0,1,2} to the given uhid device, * retrieve and open the matching hidraw node, diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index 1fa288b76cd5..f539a7a223cf 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -443,3 +443,82 @@ SEC(".struct_ops.link") struct hid_bpf_ops test_infinite_loop_output_report = { .hid_hw_output_report = (void *)hid_test_infinite_loop_output_report, }; + +struct elem { + struct bpf_wq work; +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct elem); +} hmap SEC(".maps"); + +static int wq_cb_sleepable(void *map, int *key, struct bpf_wq *work) +{ + __u8 buf[9] = {2, 3, 4, 5, 6, 7, 8, 9, 10}; + struct hid_bpf_ctx *hid_ctx; + + hid_ctx = hid_bpf_allocate_context(*key); + if (!hid_ctx) + return 0; /* EPERM check */ + + hid_bpf_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf)); + + hid_bpf_release_context(hid_ctx); + + return 0; +} + +static int test_inject_input_report_callback(int *key) +{ + struct elem init = {}, *val; + struct bpf_wq *wq; + + if (bpf_map_update_elem(&hmap, key, &init, 0)) + return -1; + + val = bpf_map_lookup_elem(&hmap, key); + if (!val) + return -2; + + wq = &val->work; + if (bpf_wq_init(wq, &hmap, 0) != 0) + return -3; + + if (bpf_wq_set_callback(wq, wq_cb_sleepable, 0)) + return -4; + + if (bpf_wq_start(wq, 0)) + return -5; + + return 0; +} + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_multiply_events_wq, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) +{ + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */); + int hid = hid_ctx->hid->id; + int ret; + + if (!data) + return 0; /* EPERM check */ + + if (data[0] != 1) + return 0; + + ret = test_inject_input_report_callback(&hid); + if (ret) + return ret; + + data[1] += 5; + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_multiply_events_wq = { + .hid_device_event = (void *)hid_test_multiply_events_wq, +}; diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h index e02e24e3eab3..8014383846d2 100644 --- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h @@ -90,4 +90,13 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx, __u8 *data, size_t buf__sz) __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_impl(struct bpf_wq *wq, + int (callback_fn)(void *map, int *key, struct bpf_wq *wq), + unsigned int flags__k, void *aux__ign) __ksym; +#define bpf_wq_set_callback(timer, cb, flags) \ + bpf_wq_set_callback_impl(timer, cb, flags, NULL) + #endif /* __HID_BPF_HELPERS_H */ From 9acbb7ba4589d4715141d4e14230a828ddc95f3d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:32 +0200 Subject: [PATCH 41/60] HID: bpf: allow hid_device_event hooks to inject input reports on self This is the same logic than hid_hw_raw_request or hid_hw_output_report: we can allow hid_bpf_try_input_report to be called from a hook on hid_input_report if we ensure that the call can not be made twice in a row. There is one extra subtlety in which there is a lock in hid_input_report. But given that we can detect if we are already in the hook, we can notify hid_input_report to not take the lock. This is done by checking if ctx_kern data is valid or null, and if it is equal to the dedicated incoming data buffer. In order to have more control on whether the lock needs to be taken or not we introduce a new kfunc for it: hid_bpf_try_input_report() Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-11-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- Documentation/hid/hid-bpf.rst | 2 +- drivers/hid/bpf/hid_bpf_dispatch.c | 56 +++++++++++++++++++++++++----- drivers/hid/hid-core.c | 5 +-- include/linux/hid_bpf.h | 6 ++-- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst index 8ae8f49801cb..5939eeafb361 100644 --- a/Documentation/hid/hid-bpf.rst +++ b/Documentation/hid/hid-bpf.rst @@ -202,7 +202,7 @@ Available API that can be used in syscall HID-BPF programs or in sleepable HID-B ------------------------------------------------------------------------------------------------------- .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c - :identifiers: hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context + :identifiers: hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_try_input_report hid_bpf_allocate_context hid_bpf_release_context General overview of a HID-BPF program ===================================== diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 5174dc6d9d18..23daf94510bb 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL(hid_ops); u8 * dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data, - u32 *size, int interrupt, u64 source) + u32 *size, int interrupt, u64 source, bool from_bpf) { struct hid_bpf_ctx_kern ctx_kern = { .ctx = { @@ -33,6 +33,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type .size = *size, }, .data = hdev->bpf.device_data, + .from_bpf = from_bpf, }; struct hid_bpf_ops *e; int ret; @@ -488,6 +489,50 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) 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); + if (ret) + return ret; + + return hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (__u64)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 * @@ -504,7 +549,6 @@ __bpf_kfunc int hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, const size_t buf__sz) { - size_t size = buf__sz; int ret; ret = down_interruptible(&ctx->hid->driver_input_lock); @@ -512,12 +556,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf return ret; /* check arguments */ - ret = __hid_bpf_hw_check_params(ctx, buf, &size, type); - if (ret) - return ret; - - ret = hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (__u64)ctx, - true /* lock_already_taken */); + ret = __hid_bpf_input_report(ctx, type, buf, buf__sz, true /* lock_already_taken */); up(&ctx->hid->driver_input_lock); @@ -536,6 +575,7 @@ 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 = { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e9b5f44683fd..52a75afe3e7d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2027,7 +2027,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt, u64 source, + u8 *data, u32 size, int interrupt, u64 source, bool from_bpf, bool lock_already_taken) { struct hid_report_enum *report_enum; @@ -2053,7 +2053,7 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, report_enum = hid->report_enum + type; hdrv = hid->driver; - data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source); + data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source, from_bpf); if (IS_ERR(data)) { ret = PTR_ERR(data); goto unlock; @@ -2105,6 +2105,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data int interrupt) { return __hid_input_report(hid, type, data, size, interrupt, 0, + false, /* from_bpf */ false /* lock_already_taken */); } EXPORT_SYMBOL_GPL(hid_input_report); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 7f04353d09e9..93546ee7677a 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -72,7 +72,7 @@ struct hid_ops { int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source, bool from_bpf); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt, u64 source, + u8 *data, u32 size, int interrupt, u64 source, bool from_bpf, bool lock_already_taken); struct module *owner; const struct bus_type *bus_type; @@ -195,7 +195,7 @@ struct hid_bpf { #ifdef CONFIG_HID_BPF u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, - u32 *size, int interrupt, u64 source); + u32 *size, int interrupt, u64 source, bool from_bpf); int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, u32 size, enum hid_report_type rtype, @@ -211,7 +211,7 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s #else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 *size, int interrupt, - u64 source) { return data; } + u64 source, bool from_bpf) { return data; } static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, unsigned char reportnum, u8 *buf, u32 size, enum hid_report_type rtype, From 62f2e1a096cd4380eca7e55fa4369d50a8536ab8 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:33 +0200 Subject: [PATCH 42/60] selftests/hid: add another test for injecting an event from an event hook Similar to test_multiply_events_wq: we receive one event and inject a new one. But given that this time we are already in the event hook, we can use hid_bpf_try_input_report() directly as this function will not sleep. Note that the injected event gets processed before the original one this way. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-12-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 36 +++++++++++++++++ tools/testing/selftests/hid/progs/hid.c | 39 +++++++++++++++++++ .../selftests/hid/progs/hid_bpf_helpers.h | 4 ++ 3 files changed, 79 insertions(+) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index 31637b3b8db5..36bbad8e0f9f 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -1168,6 +1168,42 @@ TEST_F(hid_bpf, test_multiply_events_wq) ASSERT_EQ(buf[1], 3); } +/* + * Attach hid_multiply_event to the given uhid device, + * retrieve and open the matching hidraw node, + * inject one event in the uhid device, + * check that the program sees it and can add extra data + */ +TEST_F(hid_bpf, test_multiply_events) +{ + const struct test_program progs[] = { + { .name = "hid_test_multiply_events" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* inject one event */ + buf[0] = 1; + buf[1] = 42; + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 2); + ASSERT_EQ(buf[1], 47); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 2); + ASSERT_EQ(buf[1], 52); +} + /* * Attach hid_insert{0,1,2} to the given uhid device, * retrieve and open the matching hidraw node, diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index f539a7a223cf..46feeb91d1d5 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -522,3 +522,42 @@ SEC(".struct_ops.link") struct hid_bpf_ops test_multiply_events_wq = { .hid_device_event = (void *)hid_test_multiply_events_wq, }; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_multiply_events, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type) +{ + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */); + __u8 buf[9]; + int ret; + + if (!data) + return 0; /* EPERM check */ + + if (data[0] != 1) + return 0; + + /* + * we have to use an intermediate buffer as hid_bpf_input_report + * will memset data to \0 + */ + __builtin_memcpy(buf, data, sizeof(buf)); + + buf[0] = 2; + buf[1] += 5; + ret = hid_bpf_try_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf)); + if (ret < 0) + return ret; + + /* + * In real world we should reset the original buffer as data might be garbage now, + * but it actually now has the content of 'buf' + */ + data[1] += 5; + + return 9; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_multiply_events = { + .hid_device_event = (void *)hid_test_multiply_events, +}; diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h index 8014383846d2..c72e44321764 100644 --- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h @@ -89,6 +89,10 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, __u8 *data, size_t buf__sz) __ksym; +extern int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, + enum hid_report_type type, + __u8 *data, + size_t buf__sz) __ksym; /* bpf_wq implementation */ extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym; From d3e15189bfd4d0a9d3a7ad8bd0e6ebb1c0419f93 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Jun 2024 15:46:34 +0200 Subject: [PATCH 43/60] selftests/hid: add an infinite loop test for hid_bpf_try_input_report We don't want this call to allow an infinite loop in HID-BPF, so let's have some tests. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-13-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/hid_bpf.c | 41 +++++++++++++++++++++++++ tools/testing/selftests/hid/progs/hid.c | 37 ++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/tools/testing/selftests/hid/hid_bpf.c b/tools/testing/selftests/hid/hid_bpf.c index 36bbad8e0f9f..dc0408a831d0 100644 --- a/tools/testing/selftests/hid/hid_bpf.c +++ b/tools/testing/selftests/hid/hid_bpf.c @@ -1204,6 +1204,47 @@ TEST_F(hid_bpf, test_multiply_events) ASSERT_EQ(buf[1], 52); } +/* + * Call hid_bpf_input_report against the given uhid device, + * check that the program is not making infinite loops. + */ +TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call) +{ + const struct test_program progs[] = { + { .name = "hid_test_infinite_loop_input_report" }, + }; + __u8 buf[10] = {0}; + int err; + + LOAD_PROGRAMS(progs); + + /* emit hid_hw_output_report from hidraw */ + buf[0] = 1; /* report ID */ + buf[1] = 2; + buf[2] = 42; + + uhid_send_event(_metadata, self->uhid_fd, buf, 6); + + /* read the data from hidraw */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[1], 3); + + /* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); + ASSERT_EQ(buf[0], 1); + ASSERT_EQ(buf[1], 4); + + /* read the data from hidraw: there should be none */ + memset(buf, 0, sizeof(buf)); + err = read(self->hidraw_fd, buf, sizeof(buf)); + ASSERT_EQ(err, -1) TH_LOG("read_hidraw"); +} + /* * Attach hid_insert{0,1,2} to the given uhid device, * retrieve and open the matching hidraw node, diff --git a/tools/testing/selftests/hid/progs/hid.c b/tools/testing/selftests/hid/progs/hid.c index 46feeb91d1d5..ee9bbbcf751b 100644 --- a/tools/testing/selftests/hid/progs/hid.c +++ b/tools/testing/selftests/hid/progs/hid.c @@ -561,3 +561,40 @@ SEC(".struct_ops.link") struct hid_bpf_ops test_multiply_events = { .hid_device_event = (void *)hid_test_multiply_events, }; + +SEC("?struct_ops/hid_device_event") +int BPF_PROG(hid_test_infinite_loop_input_report, struct hid_bpf_ctx *hctx, + enum hid_report_type report_type, __u64 source) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 6 /* size */); + __u8 buf[6]; + + if (!data) + return 0; /* EPERM check */ + + /* + * we have to use an intermediate buffer as hid_bpf_input_report + * will memset data to \0 + */ + __builtin_memcpy(buf, data, sizeof(buf)); + + /* always forward the request as-is to the device, hid-bpf should prevent + * infinite loops. + * the return value is ignored so the event is passing to userspace. + */ + + hid_bpf_try_input_report(hctx, report_type, buf, sizeof(buf)); + + /* each time we process the event, we increment by one data[1]: + * after each successful call to hid_bpf_try_input_report, buf + * has been memcopied into data by the kernel. + */ + data[1] += 1; + + return 0; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops test_infinite_loop_input_report = { + .hid_device_event = (void *)hid_test_infinite_loop_input_report, +}; From fcdf830ea634cf0ee6543b6cd6a4932f92464fc7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Jul 2024 14:39:49 +0200 Subject: [PATCH 44/60] selftests/hid: ensure CKI can compile our new tests on old kernels In the same way than commit ae7487d112cf ("selftests/hid: ensure we can compile the tests on kernels pre-6.3") we should expose struct hid_bpf_ops when it's not available in vmlinux.h. So unexpose an eventual struct hid_bpf_ops, include vmlinux.h, and re-export struct hid_bpf_ops. Fixes: d7696738d66b ("selftests/hid: convert the hid_bpf selftests with struct_ops") Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202406270328.bscLN1IF-lkp@intel.com/ Link: https://patch.msgid.link/20240701-fix-cki-v2-1-20564e2e1393@kernel.org Signed-off-by: Benjamin Tissoires --- .../selftests/hid/progs/hid_bpf_helpers.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h index c72e44321764..cfe37f491906 100644 --- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h @@ -7,6 +7,7 @@ /* "undefine" structs and enums in vmlinux.h, because we "override" them below */ #define hid_bpf_ctx hid_bpf_ctx___not_used +#define hid_bpf_ops hid_bpf_ops___not_used #define hid_report_type hid_report_type___not_used #define hid_class_request hid_class_request___not_used #define hid_bpf_attach_flags hid_bpf_attach_flags___not_used @@ -24,6 +25,7 @@ #include "vmlinux.h" #undef hid_bpf_ctx +#undef hid_bpf_ops #undef hid_report_type #undef hid_class_request #undef hid_bpf_attach_flags @@ -68,6 +70,20 @@ enum hid_class_request { HID_REQ_SET_PROTOCOL = 0x0B, }; +struct hid_bpf_ops { + int hid_id; + u32 flags; + struct list_head list; + int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, + u64 source); + int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx); + int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, + enum hid_report_type rtype, enum hid_class_request reqtype, + u64 source); + int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); + struct hid_device *hdev; +}; + #ifndef BPF_F_BEFORE #define BPF_F_BEFORE (1U << 3) #endif From 762ced1630a97a457ad2fd5f5a36849009808431 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Jul 2024 14:39:50 +0200 Subject: [PATCH 45/60] HID: bpf: fix gcc warning and unify __u64 into u64 I've got multiple reports of: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]. Let's use the same trick than kernel/bpf/helpers.c to shut up that warning. Even if we were on an architecture with addresses on more than 64 bits, this isn't much of an issue as the address is not used as a pointer, but as an hash and the caller is not supposed to go back to the kernel address ever. And while we change those, make sure we use u64 instead of __u64 for consistency Reported-by: Stephen Rothwell Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202406280633.OPB5uIFj-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202406282304.UydSVncq-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202406282242.Fk738zzy-lkp@intel.com/ Reported-by: Mirsad Todorovac Fixes: 67eccf151d76 ("HID: add source argument to HID low level functions") Link: https://patch.msgid.link/20240701-fix-cki-v2-2-20564e2e1393@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 6 +++--- drivers/hid/bpf/hid_bpf_struct_ops.c | 2 +- drivers/hid/hid-core.c | 4 ++-- drivers/hid/hidraw.c | 6 +++--- include/linux/hid_bpf.h | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 23daf94510bb..a36e680399fe 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -440,7 +440,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, size, rtype, reqtype, - (__u64)ctx, + (u64)(long)ctx, true); /* prevent infinite recursions */ if (ret > 0) @@ -483,7 +483,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) if (!dma_data) return -ENOMEM; - ret = hid_ops->hid_hw_output_report(hdev, dma_data, size, (__u64)ctx, true); + ret = hid_ops->hid_hw_output_report(hdev, dma_data, size, (u64)(long)ctx, true); kfree(dma_data); return ret; @@ -505,7 +505,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *b if (ret) return ret; - return hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (__u64)ctx, true, + return hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (u64)(long)ctx, true, lock_already_taken); } diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c index 37d2f8e2413a..b03b44ad3458 100644 --- a/drivers/hid/bpf/hid_bpf_struct_ops.c +++ b/drivers/hid/bpf/hid_bpf_struct_ops.c @@ -261,7 +261,7 @@ static void hid_bpf_unreg(void *kdata) hid_put_device(hdev); } -static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type, __u64 source) +static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type, u64 source) { return 0; } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 52a75afe3e7d..0f797dab975b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2412,7 +2412,7 @@ int __hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source, bool from_bpf) + u64 source, bool from_bpf) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; int ret; @@ -2454,7 +2454,7 @@ int hid_hw_raw_request(struct hid_device *hdev, } EXPORT_SYMBOL_GPL(hid_hw_raw_request); -int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source, +int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, u64 source, bool from_bpf) { unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index c2396916cdaa..716294e40e8a 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, if ((report_type == HID_OUTPUT_REPORT) && !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) { - ret = __hid_hw_output_report(dev, buf, count, (__u64)file, false); + ret = __hid_hw_output_report(dev, buf, count, (u64)(long)file, false); /* * compatibility with old implementation of USB-HID and I2C-HID: * if the device does not support receiving output reports, @@ -151,7 +151,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, } ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type, - HID_REQ_SET_REPORT, (__u64)file, false); + HID_REQ_SET_REPORT, (u64)(long)file, false); out_free: kfree(buf); @@ -228,7 +228,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t } ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type, - HID_REQ_GET_REPORT, (__u64)file, false); + HID_REQ_GET_REPORT, (u64)(long)file, false); if (ret < 0) goto out_free; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 93546ee7677a..3f6584014311 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -68,9 +68,9 @@ struct hid_ops { unsigned char reportnum, __u8 *buf, size_t len, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source, bool from_bpf); + u64 source, bool from_bpf); int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, - __u64 source, bool from_bpf); + u64 source, bool from_bpf); int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, int interrupt, u64 source, bool from_bpf, bool lock_already_taken); @@ -115,7 +115,7 @@ struct hid_bpf_ops { * Context: Interrupt context. */ int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, - __u64 source); + u64 source); /** * @hid_rdesc_fixup: called when the probe function parses the report descriptor From 260ffc9676b635c2ededc39285bfa41f83536ee1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Jul 2024 14:39:51 +0200 Subject: [PATCH 46/60] HID: bpf: doc fixes for hid_hw_request() hooks We had the following errors while doing make htmldocs: Documentation/hid/hid-bpf:185: include/linux/hid_bpf.h:144: ERROR: Unexpected indentation. Documentation/hid/hid-bpf:185: include/linux/hid_bpf.h:145: WARNING: Block quote ends without a blank line; unexpected unindent. Documentation/hid/hid-bpf:185: include/linux/hid_bpf.h:147: ERROR: Unexpected indentation. Reported-by: Stephen Rothwell Fixes: 8bd0488b5ea5 ("HID: bpf: add HID-BPF hooks for hid_hw_raw_requests") Link: https://patch.msgid.link/20240701-fix-cki-v2-3-20564e2e1393@kernel.org Signed-off-by: Benjamin Tissoires --- include/linux/hid_bpf.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 3f6584014311..c30c31b79419 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -139,12 +139,15 @@ struct hid_bpf_ops { * * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx * ``reportnum``: the report number, as in hid_hw_raw_request() + * * ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, - * ``HID_OUTPUT_REPORT``) + * ``HID_OUTPUT_REPORT``) + * * ``reqtype``: the request + * * ``source``: a u64 referring to a uniq but identifiable source. If %0, the - * kernel itself emitted that call. For hidraw, ``source`` is set - * to the associated ``struct file *``. + * kernel itself emitted that call. For hidraw, ``source`` is set + * to the associated ``struct file *``. * * Return: %0 to keep processing the request by hid-core; any other value * stops hid-core from processing that event. A positive value should be @@ -153,7 +156,7 @@ struct hid_bpf_ops { */ int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, enum hid_report_type rtype, enum hid_class_request reqtype, - __u64 source); + u64 source); /** * @hid_hw_output_report: called whenever a hid_hw_output_report() call is emitted From c79de517a226b86419a5baa867e65e3f8118829f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Jul 2024 14:39:52 +0200 Subject: [PATCH 47/60] HID: bpf: doc fixes for hid_hw_request() hooks We had the following errors while doing make htmldocs: Documentation/hid/hid-bpf:185: include/linux/hid_bpf.h:167: ERROR: Unexpected indentation. Also ensure consistency with the rest of the __u64 vs u64. Reported-by: Stephen Rothwell Fixes: 9286675a2aed ("HID: bpf: add HID-BPF hooks for hid_hw_output_report") Link: https://patch.msgid.link/20240701-fix-cki-v2-4-20564e2e1393@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 2 +- include/linux/hid_bpf.h | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index a36e680399fe..a272a086c950 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -115,7 +115,7 @@ out: EXPORT_SYMBOL_GPL(dispatch_hid_bpf_raw_requests); int dispatch_hid_bpf_output_report(struct hid_device *hdev, - __u8 *buf, u32 size, __u64 source, + __u8 *buf, u32 size, u64 source, bool from_bpf) { struct hid_bpf_ctx_kern ctx_kern = { diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index c30c31b79419..9ca96fc90449 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -138,6 +138,7 @@ struct hid_bpf_ops { * It has the following arguments: * * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * * ``reportnum``: the report number, as in hid_hw_raw_request() * * ``rtype``: the report type (``HID_INPUT_REPORT``, ``HID_FEATURE_REPORT``, @@ -165,16 +166,17 @@ struct hid_bpf_ops { * It has the following arguments: * * ``ctx``: The HID-BPF context as &struct hid_bpf_ctx + * * ``source``: a u64 referring to a uniq but identifiable source. If %0, the - * kernel itself emitted that call. For hidraw, ``source`` is set - * to the associated ``struct file *``. + * kernel itself emitted that call. For hidraw, ``source`` is set + * to the associated ``struct file *``. * * Return: %0 to keep processing the request by hid-core; any other value * stops hid-core from processing that event. A positive value should be * returned with the number of bytes written to the device; a negative error * code interrupts the processing of this call. */ - int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, __u64 source); + int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source); /* private: do not show up in the docs */ @@ -203,9 +205,9 @@ 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); + u64 source, bool from_bpf); int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size, - __u64 source, bool from_bpf); + u64 source, bool from_bpf); int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); @@ -221,7 +223,7 @@ static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev, enum hid_class_request reqtype, u64 source, bool from_bpf) { return 0; } static inline int dispatch_hid_bpf_output_report(struct hid_device *hdev, __u8 *buf, u32 size, - __u64 source, bool from_bpf) { return 0; } + u64 source, bool from_bpf) { return 0; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} From 8a89db51873ca574de45b25fce68103f34266459 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:17 +0200 Subject: [PATCH 48/60] HID: bpf: Add a HID report composition helper macros These macros make it slightly easier and more modular to create a HID report descriptor from scratch. Since they carry the annotation we don't need to comment it and they cannot get stale. For comparison, before we had this: 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x04, // Report Count (4) 0x75, 0x01, // Report Size (1) Now we can write this as: LogicalRange_i8(0, 1) ReportCount(4) ReportSize(1) Because these macros are for creating new report descriptors, some bits aren't directly exposed. e.g in the example above: there is a logical range as one macro that sets both min and max. There is seldom a good use case for skipping either anyway. These macros will need to be expanded over time. For Usage Pages and Usage IDs, we use a tool to parse the HUT JSON (attached to the HUT 1.5 PDF [1]) and generate all #defines for all usage pages and usages in the form: #define UsagePage_Foo_Bar #define Usage_FB_SomeOrOther Where the FB is simply the acronym based on the capital letters in the Usage Page name or the first three letters, whichever makes slightly more sense. [1] https://usb.org/document-library/hid-usage-tables-15 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/92 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/96 Signed-off-by: Peter Hutterer Link: https://patch.msgid.link/20240627-import-bpf-v1-1-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/hid_report_helpers.h | 2960 ++++++++++++++++++++ 1 file changed, 2960 insertions(+) create mode 100644 drivers/hid/bpf/progs/hid_report_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 000000000000..0aa1df438eeb --- /dev/null +++ b/drivers/hid/bpf/progs/hid_report_helpers.h @@ -0,0 +1,2960 @@ +/* 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) + * LogicalRange_i8(0, 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 + +/* 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 ReportId(id_) 0x85, i8(id_), +#define ReportSize(sz_) 0x75, i8(sz_), +#define ReportCount(cnt_) 0x95, i8(cnt_), + +#define LogicalRange_i8(min_, max_) 0x15, i8(min_), 0x25, i8(max_), +#define LogicalRange_i16(min_, max_) 0x16, LE16(min_), 0x26, LE16(max_), +#define LogicalRange_i32(min_, max_) 0x17, LE32(min_), 0x27, LE32(max_), + +#define PhysicalRange_i8(min_, max_) 0x35, i8(min_), 0x45, i8(max_), +#define PhysicalRange_i16(min_, max_) 0x36, LE16(min_), 0x46, LE16(max_), +#define PhysicalRange_i32(min_, max_) 0x37, LE32(min_), 0x47, LE32(max_), + +#define UsageRange_i8(min_, max_) 0x19, i8(min_), 0x29, i8(max_), +#define UsageRange_i16(min_, max_) 0x1a, LE16(min_), 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. + * + * HID-BPF requires that at least one report has + * the same size as the 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_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_Rechargable 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) From 09c555faedb855b07d62503e0a4cd8cdf726da20 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:18 +0200 Subject: [PATCH 49/60] HID: bpf: add a driver for the Huion Inspiroy 2S (H641P) This is a a driver for the Huion Inspiroy 2S in both modes (firmware mode and tablet mode). This device has 6 buttons and a wheel, all of which send key combinations (see the comments for the defaults). Luckily the device is quite limited in that it only supports one button down at a time, so with this BPF we can simply remap the 8 possible report IDs to our own custom-built report descriptor. If the device is in tablet mode (e.g. using huion-switcher it sends everything through the vendor report instead). This BPF program converts both, depending which devices you attach to you get both. Or if you attach to all hid devices you get a duplicate device but it'll work either way. This BPF should be mostly compatible for the M and L as well though they have more buttons so the rdescs will need some minor rework. Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/85 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/109 Signed-off-by: Peter Hutterer Link: https://patch.msgid.link/20240627-import-bpf-v1-2-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- .../hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c | 534 ++++++++++++++++++ 1 file changed, 534 insertions(+) create mode 100644 drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c 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 000000000000..b09b80132368 --- /dev/null +++ b/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c @@ -0,0 +1,534 @@ +// 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 + +#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; + +static const __u8 fixed_rdesc_pad[] = { + UsagePage_GenericDesktop + Usage_GD_Keypad + CollectionApplication( + // -- Byte 0 in report + ReportId(PAD_REPORT_ID) + LogicalRange_i8(0, 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 + LogicalRange_i8(-1, 1) + ReportCount(1) + ReportSize(8) + Input(Var|Rel) + // Byte 5 is the button state + UsagePage_Button + UsageRange_i8(0x01, 0x6) + LogicalRange_i8(0x01, 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 + LogicalRange_i8(0, 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) + PhysicalRange_i16(0, 160) + LogicalRange_i16(0, 32767) + Usage_GD_X + Input(Var|Abs) // Bytes 2+3 + PhysicalRange_i16(0, 100) + LogicalRange_i16(0, 32767) + Usage_GD_Y + Input(Var|Abs) // Bytes 4+5 + ) + UsagePage_Digitizers + Usage_Dig_TipPressure + LogicalRange_i16(0, 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 + LogicalRange_i8(0, 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 + LogicalRange_i16(0, 32000) + PhysicalRange_i16(0, 160) + // Bytes 2/3 in report + Usage_GD_X + Input(Var|Abs) + LogicalRange_i16(0, 20000) + PhysicalRange_i16(0, 100) + // Bytes 4/5 in report + Usage_GD_Y + Input(Var|Abs) + ) + // Bytes 6/7 in report + LogicalRange_i16(0, 8192) + Usage_Dig_TipPressure + Input(Var|Abs) + ) + ) + UsagePage_GenericDesktop + Usage_GD_Keypad + CollectionApplication( + // Byte 0 + ReportId(PAD_REPORT_ID) + LogicalRange_i8(0, 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 + UsageRange_i8(0x01, 0x6) + LogicalRange_i8(0x0, 0x1) + ReportCount(6) + ReportSize(1) + Input(Var|Abs) + ReportCount(2) + Input(Const) + // Byte 5 is the wheel + UsagePage_GenericDesktop + Usage_GD_Wheel + LogicalRange_i8(-1, 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); + } + + /* 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"; From c4015aa7d8faa43ca53608dccad681eafc22db09 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:19 +0200 Subject: [PATCH 50/60] HID: bpf: move the BIT() macro to hid_bpf_helpers.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This macro can be useful in mopre than one place Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/commit/7970a9c17aa0756bad63e89fccb6ee4f2ec83ccc Signed-off-by: José Expósito Link: https://patch.msgid.link/20240627-import-bpf-v1-3-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/XPPen__Artist24.bpf.c | 2 -- drivers/hid/bpf/progs/hid_bpf_helpers.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c index d4d062c3a653..c24fe905c50d 100644 --- a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c +++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c @@ -78,8 +78,6 @@ static const __u8 fixed_rdesc[] = { 0xc0, // End Collection 106 }; -#define BIT(n) (1UL << n) - #define TIP_SWITCH BIT(0) #define BARREL_SWITCH BIT(1) #define ERASER BIT(2) diff --git a/drivers/hid/bpf/progs/hid_bpf_helpers.h b/drivers/hid/bpf/progs/hid_bpf_helpers.h index 8f226f6e886b..3ba24d125a08 100644 --- a/drivers/hid/bpf/progs/hid_bpf_helpers.h +++ b/drivers/hid/bpf/progs/hid_bpf_helpers.h @@ -66,6 +66,7 @@ extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, #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 From f03741540dbab48f8a65da44aaadbe04216d9a42 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:20 +0200 Subject: [PATCH 51/60] HID: bpf: Add support for the XP-PEN Deco Mini 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XP-PEN Deco Mini 4 is a UGEE device with a frame with 6 buttons. Its pen has 2 buttons and supports pressure reporting. Fix their report descriptors and transform the frame button events to support it. Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/88 Signed-off-by: José Expósito Link: https://patch.msgid.link/20240627-import-bpf-v1-4-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c | 231 +++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c 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 000000000000..46d5c459d0c9 --- /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 + +#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; + int 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"; From 9b52d81115db681efc1f83ded1d572e5b0b4fd49 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:21 +0200 Subject: [PATCH 52/60] HID: bpf: Add Huion Dial 2 bpf fixup Pretty much similar to the Inspiroy 2, but with 2 wheels and 8 buttons. This bpf also works in both normal and vendor mode. If the device is switched into vendor mode by huion-switcher, a udev property is set which is then retrieved by this bpf object. This allows to hide the now unused normal collections. Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/103 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/104 Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/111 Link: https://patch.msgid.link/20240627-import-bpf-v1-5-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Huion__Dial-2.bpf.c | 614 ++++++++++++++++++++++ drivers/hid/bpf/progs/hid_bpf.h | 1 + 2 files changed, 615 insertions(+) create mode 100644 drivers/hid/bpf/progs/Huion__Dial-2.bpf.c 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 000000000000..2411dec6db08 --- /dev/null +++ b/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c @@ -0,0 +1,614 @@ +// 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 + +#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) + LogicalRange_i8(0, 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 + LogicalRange_i8(-1, 1) + ReportCount(1) + ReportSize(8) + Input(Var|Rel) + // Byte 5 is the button state + UsagePage_Button + UsageRange_i8(0x01, 0x8) + LogicalRange_i8(0x0, 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 + LogicalRange_i8(0, 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) + PhysicalRange_i16(0, 266) + LogicalRange_i16(0, 32767) + Usage_GD_X + Input(Var|Abs) // Bytes 2+3 + PhysicalRange_i16(0, 166) + LogicalRange_i16(0, 32767) + Usage_GD_Y + Input(Var|Abs) // Bytes 4+5 + ) + UsagePage_Digitizers + Usage_Dig_TipPressure + LogicalRange_i16(0, 8191) + Input(Var|Abs) // Byte 6+7 + ReportSize(8) + ReportCount(2) + LogicalRange_i8(-60, 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 + LogicalRange_i8(0, 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 + LogicalRange_i16(0, 53340) + PhysicalRange_i16(0, 266) + // Bytes 2/3 in report + Usage_GD_X + Input(Var|Abs) + LogicalRange_i16(0, 33340) + PhysicalRange_i16(0, 166) + // Bytes 4/5 in report + Usage_GD_Y + Input(Var|Abs) + ) + // Bytes 6/7 in report + LogicalRange_i16(0, 8191) + Usage_Dig_TipPressure + Input(Var|Abs) + // Bytes 8/9 in report + ReportCount(1) // Padding + Input(Const) + LogicalRange_i8(-60, 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) + LogicalRange_i8(0, 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 + UsageRange_i8(0x01, 0x8) + LogicalRange_i8(0x0, 0x1) + ReportCount(8) + ReportSize(1) + Input(Var|Abs) + // Byte 5 is the top dial + UsagePage_GenericDesktop + Usage_GD_Wheel + LogicalRange_i8(-1, 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/hid_bpf.h b/drivers/hid/bpf/progs/hid_bpf.h index 8c1cd9e25bc3..7cabd1b2e837 100644 --- a/drivers/hid/bpf/progs/hid_bpf.h +++ b/drivers/hid/bpf/progs/hid_bpf.h @@ -9,6 +9,7 @@ #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; From f58e7f404da44c94e46bfe657b8707195aebd25a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 27 Jun 2024 11:54:22 +0200 Subject: [PATCH 53/60] HID: bpf: Thrustmaster TCA Yoke Boeing joystick fix This joystick's original HID descriptor is wrong & it shows a ABS_MISC axis in Linux that doesn't exist on the hardware. Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/82 Signed-off-by: K S Iyer Link: https://patch.msgid.link/20240627-import-bpf-v1-6-0dbcda4a5b1f@kernel.org Signed-off-by: Benjamin Tissoires --- .../progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c 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 000000000000..ecf775a99346 --- /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 + +#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"; From 394ba612f9419ec5bfebbffb72212fd3b2094986 Mon Sep 17 00:00:00 2001 From: Orlando Chamberlain Date: Wed, 3 Jul 2024 17:54:11 +0000 Subject: [PATCH 54/60] HID: apple: Add support for magic keyboard backlight on T2 Macs Unlike T2 Macs with Butterfly keyboard, who have their keyboard backlight on the USB device the T2 Macs with Magic keyboard have their backlight on the Touchbar backlight device (05ac:8102). Support for Butterfly keyboards has already been added in commit 9018eacbe623 ("HID: apple: Add support for keyboard backlight on certain T2 Macs.") This patch adds support for the Magic keyboards. Signed-off-by: Orlando Chamberlain Co-developed-by: Aditya Garg Signed-off-by: Aditya Garg Link: https://patch.msgid.link/E1D444EA-7FD0-42DA-B198-50B0F03298FB@live.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-apple.c | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index bd022e004356..6dedb84d7cc3 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -8,6 +8,8 @@ * Copyright (c) 2006-2007 Jiri Kosina * Copyright (c) 2008 Jiri Slaby * Copyright (c) 2019 Paul Pawlowski + * Copyright (c) 2023 Orlando Chamberlain + * Copyright (c) 2024 Aditya Garg */ /* @@ -23,6 +25,7 @@ #include #include #include +#include #include "hid-ids.h" @@ -38,12 +41,17 @@ #define APPLE_RDESC_BATTERY BIT(9) #define APPLE_BACKLIGHT_CTL BIT(10) #define APPLE_IS_NON_APPLE BIT(11) +#define APPLE_MAGIC_BACKLIGHT BIT(12) #define APPLE_FLAG_FKEY 0x01 #define HID_COUNTRY_INTERNATIONAL_ISO 13 #define APPLE_BATTERY_TIMEOUT_MS 60000 +#define HID_USAGE_MAGIC_BL 0xff00000f +#define APPLE_MAGIC_REPORT_ID_POWER 3 +#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1 + static unsigned int fnmode = 3; module_param(fnmode, uint, 0644); MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " @@ -81,6 +89,12 @@ struct apple_sc_backlight { struct hid_device *hdev; }; +struct apple_magic_backlight { + struct led_classdev cdev; + struct hid_report *brightness; + struct hid_report *power; +}; + struct apple_sc { struct hid_device *hdev; unsigned long quirks; @@ -822,6 +836,66 @@ cleanup_and_exit: return ret; } +static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate) +{ + rep->field[0]->value[0] = value; + rep->field[1]->value[0] = 0x5e; /* Mimic Windows */ + rep->field[1]->value[0] |= rate << 8; + + hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT); +} + +static void apple_magic_backlight_set(struct apple_magic_backlight *backlight, + int brightness, char rate) +{ + apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate); + if (brightness) + apple_magic_backlight_report_set(backlight->brightness, brightness, rate); +} + +static int apple_magic_backlight_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct apple_magic_backlight *backlight = container_of(led_cdev, + struct apple_magic_backlight, cdev); + + apple_magic_backlight_set(backlight, brightness, 1); + return 0; +} + +static int apple_magic_backlight_init(struct hid_device *hdev) +{ + struct apple_magic_backlight *backlight; + struct hid_report_enum *report_enum; + + /* + * Ensure this usb endpoint is for the keyboard backlight, not touchbar + * backlight. + */ + if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL) + return -ENODEV; + + backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL); + if (!backlight) + return -ENOMEM; + + report_enum = &hdev->report_enum[HID_FEATURE_REPORT]; + backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS]; + backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER]; + + if (!backlight->brightness || !backlight->power) + return -ENODEV; + + backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT; + backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum; + backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set; + + apple_magic_backlight_set(backlight, 0, 0); + + return devm_led_classdev_register(&hdev->dev, &backlight->cdev); + +} + static int apple_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -860,7 +934,18 @@ static int apple_probe(struct hid_device *hdev, if (quirks & APPLE_BACKLIGHT_CTL) apple_backlight_init(hdev); + if (quirks & APPLE_MAGIC_BACKLIGHT) { + ret = apple_magic_backlight_init(hdev); + if (ret) + goto out_err; + } + return 0; + +out_err: + del_timer_sync(&asc->battery_timer); + hid_hw_stop(hdev); + return ret; } static void apple_remove(struct hid_device *hdev) @@ -1073,6 +1158,8 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT), + .driver_data = APPLE_MAGIC_BACKLIGHT }, { } }; From 3a904d2c771115154380caaae7ffaaf0095fb88f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 5 Jul 2024 14:07:06 +0200 Subject: [PATCH 55/60] HID: fix for amples in for-6.11/bpf To: Jiri Kosina Cc: linux-input@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Benjamin Tissoires --- Changes in v2: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v1: https://lore.kernel.org/r/20240705-for-6-11-bpf-v1-1-1960e3165c9e@kernel.org --- b4-submit-tracking --- # This section is used internally by b4 prep for tracking purposes. { "series": { "revision": 2, "change-id": "20240705-for-6-11-bpf-a349efc08df8", "prefixes": [], "history": { "v1": [ "20240705-for-6-11-bpf-v1-1-1960e3165c9e@kernel.org" ] } } } From a67a1deb11d9a692366100d9ba9fb3aeb0c7707b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 5 Jul 2024 14:06:22 +0200 Subject: [PATCH 56/60] HID: samples: fix the 2 struct_ops definitions Turns out that this is not compiling anymore because the hid_bpf_ops struct_ops definition had a change during the revisions. Fixes: e342d6f6f7d8 ("HID: samples: convert the 2 HID-BPF samples into struct_ops") Signed-off-by: Benjamin Tissoires --- samples/hid/hid_mouse.bpf.c | 8 ++++---- samples/hid/hid_surface_dial.bpf.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/hid/hid_mouse.bpf.c b/samples/hid/hid_mouse.bpf.c index bd901fa855c9..f7f722dcf56d 100644 --- a/samples/hid/hid_mouse.bpf.c +++ b/samples/hid/hid_mouse.bpf.c @@ -67,7 +67,7 @@ static int hid_x_event(struct hid_bpf_ctx *hctx) return 0; } -SEC("struct_ops/device_event") +SEC("struct_ops/hid_device_event") int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx, enum hid_report_type type) { int ret = hid_y_event(hctx); @@ -79,7 +79,7 @@ int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx, enum hid_report_type type) } -SEC("struct_ops/rdesc_fixup") +SEC("struct_ops/hid_rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); @@ -121,8 +121,8 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) SEC(".struct_ops.link") struct hid_bpf_ops mouse_invert = { - .rdesc_fixup = (void *)hid_rdesc_fixup, - .device_event = (void *)hid_event, + .hid_rdesc_fixup = (void *)hid_rdesc_fixup, + .hid_device_event = (void *)hid_event, }; char _license[] SEC("license") = "GPL"; diff --git a/samples/hid/hid_surface_dial.bpf.c b/samples/hid/hid_surface_dial.bpf.c index d8d0fb07391f..527d584812ab 100644 --- a/samples/hid/hid_surface_dial.bpf.c +++ b/samples/hid/hid_surface_dial.bpf.c @@ -10,7 +10,7 @@ #define HID_UP_BUTTON 0x0009 #define HID_GD_WHEEL 0x0038 -SEC("struct_ops/device_event") +SEC("struct_ops/hid_device_event") int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */); @@ -101,7 +101,7 @@ int set_haptic(struct haptic_syscall_args *args) } /* Convert REL_DIAL into REL_WHEEL */ -SEC("struct_ops/rdesc_fixup") +SEC("struct_ops/hid_rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); @@ -132,8 +132,8 @@ int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) SEC(".struct_ops.link") struct hid_bpf_ops surface_dial = { - .rdesc_fixup = (void *)hid_rdesc_fixup, - .device_event = (void *)hid_event, + .hid_rdesc_fixup = (void *)hid_rdesc_fixup, + .hid_device_event = (void *)hid_event, }; char _license[] SEC("license") = "GPL"; From 5bd8d7071e54580a20268ffb661dafd06e1d557e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 9 Jul 2024 14:39:11 -0700 Subject: [PATCH 57/60] HID: add more missing MODULE_DESCRIPTION() macros make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-holtek-mouse.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-ite.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kensington.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-keytouch.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-kye.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lcpower.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-lenovo.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/hid/hid-winwing.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Signed-off-by: Jeff Johnson Link: https://patch.msgid.link/20240709-md-drivers-hid-v2-1-67faf2f2ec90@quicinc.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-holtek-mouse.c | 1 + drivers/hid/hid-ite.c | 1 + drivers/hid/hid-kensington.c | 1 + drivers/hid/hid-keytouch.c | 1 + drivers/hid/hid-kye.c | 1 + drivers/hid/hid-lcpower.c | 1 + drivers/hid/hid-lenovo.c | 1 + drivers/hid/hid-winwing.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c index 7c907939bfae..343730c28e2d 100644 --- a/drivers/hid/hid-holtek-mouse.c +++ b/drivers/hid/hid-holtek-mouse.c @@ -110,4 +110,5 @@ static struct hid_driver holtek_mouse_driver = { }; module_hid_driver(holtek_mouse_driver); +MODULE_DESCRIPTION("HID driver for Holtek gaming mice"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 75ebfcf31889..6a7281bc27c9 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -141,4 +141,5 @@ static struct hid_driver ite_driver = { module_hid_driver(ite_driver); MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("HID driver for some ITE \"special\" devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c index b31f7f431a3f..99e79b42047c 100644 --- a/drivers/hid/hid-kensington.c +++ b/drivers/hid/hid-kensington.c @@ -46,4 +46,5 @@ static struct hid_driver ks_driver = { }; module_hid_driver(ks_driver); +MODULE_DESCRIPTION("HID driver for Kensigton Slimblade Trackball"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-keytouch.c b/drivers/hid/hid-keytouch.c index 73bf8642dfe3..a972943baaea 100644 --- a/drivers/hid/hid-keytouch.c +++ b/drivers/hid/hid-keytouch.c @@ -48,5 +48,6 @@ static struct hid_driver keytouch_driver = { }; module_hid_driver(keytouch_driver); +MODULE_DESCRIPTION("HID driver for Keytouch devices not fully compliant with HID standard"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jiri Kosina"); diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 70ceb9437332..ca2ba3da2458 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -671,4 +671,5 @@ static struct hid_driver kye_driver = { }; module_hid_driver(kye_driver); +MODULE_DESCRIPTION("HID driver for Kye/Genius devices not fully compliant with HID standard"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c index 8acd3ee5ada5..58953d11ded7 100644 --- a/drivers/hid/hid-lcpower.c +++ b/drivers/hid/hid-lcpower.c @@ -53,4 +53,5 @@ static struct hid_driver ts_driver = { }; module_hid_driver(ts_driver); +MODULE_DESCRIPTION("HID driver for LC Power Model RC1000MCE"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index e6b2ae68b8fb..e5e72aa5260a 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -1442,4 +1442,5 @@ static struct hid_driver lenovo_driver = { }; module_hid_driver(lenovo_driver); +MODULE_DESCRIPTION("HID driver for IBM/Lenovo"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c index 0e224d1a6466..10a5d87ccb96 100644 --- a/drivers/hid/hid-winwing.c +++ b/drivers/hid/hid-winwing.c @@ -223,4 +223,5 @@ static struct hid_driver winwing_driver = { }; module_hid_driver(winwing_driver); +MODULE_DESCRIPTION("HID driver for WinWing Orion 2 throttle"); MODULE_LICENSE("GPL"); From 523e6f4f50fc7078be80434a98cc81b48a847923 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 11 Jul 2024 09:35:13 +0100 Subject: [PATCH 58/60] HID: Fix spelling mistakes "Kensigton" -> "Kensington" There are spelling mistakes in a comment and in the module description. Fix these. Signed-off-by: Colin Ian King Link: https://patch.msgid.link/20240711083513.282724-1-colin.i.king@gmail.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-kensington.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c index 99e79b42047c..16839027981f 100644 --- a/drivers/hid/hid-kensington.c +++ b/drivers/hid/hid-kensington.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * HID driver for Kensigton Slimblade Trackball + * HID driver for Kensington Slimblade Trackball * * Copyright (c) 2009 Jiri Kosina */ @@ -46,5 +46,5 @@ static struct hid_driver ks_driver = { }; module_hid_driver(ks_driver); -MODULE_DESCRIPTION("HID driver for Kensigton Slimblade Trackball"); +MODULE_DESCRIPTION("HID driver for Kensington Slimblade Trackball"); MODULE_LICENSE("GPL"); From ad1ff1f250c966b945d40a6a2e548f7d701b96df Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 9 Jul 2024 09:22:23 +0800 Subject: [PATCH 59/60] HID: mcp2221: Remove unnecessary semicolon Remove unnecessary semicolon at the end of the switch statement. This is detected by coccinelle. Signed-off-by: Chen Ni Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20240709012223.17393-1-nichen@iscas.ac.cn Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-mcp2221.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index da5ea5a23b08..0f93c22a479f 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -1048,7 +1048,7 @@ static int mcp_iio_channels(struct mcp2221 *mcp) break; default: continue; - }; + } chan->type = IIO_VOLTAGE; chan->indexed = 1; From 8a25418ba65a5d2494b369f6178a284c449bc399 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Fri, 5 Jul 2024 06:54:59 +0200 Subject: [PATCH 60/60] HID: hid-steam: Fix typo in goto label s/stream/steam/ Signed-off-by: Thorsten Blum Link: https://patch.msgid.link/20240705045458.65108-2-thorsten.blum@toblux.com Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-steam.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index f166188c21ec..a765a48c0ab5 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -1267,7 +1267,7 @@ static int steam_probe(struct hid_device *hdev, steam->client_hdev = steam_create_client_hid(hdev); if (IS_ERR(steam->client_hdev)) { ret = PTR_ERR(steam->client_hdev); - goto err_stream_unregister; + goto err_steam_unregister; } steam->client_hdev->driver_data = steam; @@ -1279,7 +1279,7 @@ static int steam_probe(struct hid_device *hdev, err_destroy: hid_destroy_device(steam->client_hdev); -err_stream_unregister: +err_steam_unregister: if (steam->connected) steam_unregister(steam); err_hw_close: