From 4156f8316324de2064f92e0d02d511f9ae74e968 Mon Sep 17 00:00:00 2001 From: "Zhang, Lixu" Date: Wed, 6 Mar 2024 00:56:37 +0000 Subject: HID: intel-ish-hid: Use PCI_VDEVICE() and rename device ID macros Use PCI_VDEVICE() to simplify the device table, and rename these IDs to follow the pattern PCI_DEVICE_ID_INTEL_*; Suggested-by: Andy Shevchenko Signed-off-by: Zhang, Lixu Reviewed-by: Andy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/hw-ish.h | 44 ++++++++++++------------- drivers/hid/intel-ish-hid/ipc/ipc.c | 14 ++++---- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 58 ++++++++++++++++----------------- 3 files changed, 58 insertions(+), 58 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h index f89b300417d7..a4484f3ba2be 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h @@ -13,28 +13,28 @@ #include "hw-ish-regs.h" #include "ishtp-dev.h" -#define CHV_DEVICE_ID 0x22D8 -#define BXT_Ax_DEVICE_ID 0x0AA2 -#define BXT_Bx_DEVICE_ID 0x1AA2 -#define APL_Ax_DEVICE_ID 0x5AA2 -#define SPT_Ax_DEVICE_ID 0x9D35 -#define CNL_Ax_DEVICE_ID 0x9DFC -#define GLK_Ax_DEVICE_ID 0x31A2 -#define CNL_H_DEVICE_ID 0xA37C -#define ICL_MOBILE_DEVICE_ID 0x34FC -#define SPT_H_DEVICE_ID 0xA135 -#define CML_LP_DEVICE_ID 0x02FC -#define CMP_H_DEVICE_ID 0x06FC -#define EHL_Ax_DEVICE_ID 0x4BB3 -#define TGL_LP_DEVICE_ID 0xA0FC -#define TGL_H_DEVICE_ID 0x43FC -#define ADL_S_DEVICE_ID 0x7AF8 -#define ADL_P_DEVICE_ID 0x51FC -#define ADL_N_DEVICE_ID 0x54FC -#define RPL_S_DEVICE_ID 0x7A78 -#define MTL_P_DEVICE_ID 0x7E45 -#define ARL_H_DEVICE_ID 0x7745 -#define ARL_S_DEVICE_ID 0x7F78 +#define PCI_DEVICE_ID_INTEL_ISH_CHV 0x22D8 +#define PCI_DEVICE_ID_INTEL_ISH_BXT_Ax 0x0AA2 +#define PCI_DEVICE_ID_INTEL_ISH_BXT_Bx 0x1AA2 +#define PCI_DEVICE_ID_INTEL_ISH_APL_Ax 0x5AA2 +#define PCI_DEVICE_ID_INTEL_ISH_SPT_Ax 0x9D35 +#define PCI_DEVICE_ID_INTEL_ISH_CNL_Ax 0x9DFC +#define PCI_DEVICE_ID_INTEL_ISH_GLK_Ax 0x31A2 +#define PCI_DEVICE_ID_INTEL_ISH_CNL_H 0xA37C +#define PCI_DEVICE_ID_INTEL_ISH_ICL_MOBILE 0x34FC +#define PCI_DEVICE_ID_INTEL_ISH_SPT_H 0xA135 +#define PCI_DEVICE_ID_INTEL_ISH_CML_LP 0x02FC +#define PCI_DEVICE_ID_INTEL_ISH_CMP_H 0x06FC +#define PCI_DEVICE_ID_INTEL_ISH_EHL_Ax 0x4BB3 +#define PCI_DEVICE_ID_INTEL_ISH_TGL_LP 0xA0FC +#define PCI_DEVICE_ID_INTEL_ISH_TGL_H 0x43FC +#define PCI_DEVICE_ID_INTEL_ISH_ADL_S 0x7AF8 +#define PCI_DEVICE_ID_INTEL_ISH_ADL_P 0x51FC +#define PCI_DEVICE_ID_INTEL_ISH_ADL_N 0x54FC +#define PCI_DEVICE_ID_INTEL_ISH_RPL_S 0x7A78 +#define PCI_DEVICE_ID_INTEL_ISH_MTL_P 0x7E45 +#define PCI_DEVICE_ID_INTEL_ISH_ARL_H 0x7745 +#define PCI_DEVICE_ID_INTEL_ISH_ARL_S 0x7F78 #define REVISION_ID_CHT_A0 0x6 #define REVISION_ID_CHT_Ax_SI 0x0 diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index a49c6affd7c4..7cc412798fdf 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -78,7 +78,7 @@ static bool check_generated_interrupt(struct ishtp_device *dev) bool interrupt_generated = true; uint32_t pisr_val = 0; - if (dev->pdev->device == CHV_DEVICE_ID) { + if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) { pisr_val = ish_reg_read(dev, IPC_REG_PISR_CHV_AB); interrupt_generated = IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val); @@ -117,7 +117,7 @@ static bool ish_is_input_ready(struct ishtp_device *dev) */ static void set_host_ready(struct ishtp_device *dev) { - if (dev->pdev->device == CHV_DEVICE_ID) { + if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) { if (dev->pdev->revision == REVISION_ID_CHT_A0 || (dev->pdev->revision & REVISION_ID_SI_MASK) == REVISION_ID_CHT_Ax_SI) @@ -909,11 +909,11 @@ static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length, */ static bool _dma_no_cache_snooping(struct ishtp_device *dev) { - return (dev->pdev->device == EHL_Ax_DEVICE_ID || - dev->pdev->device == TGL_LP_DEVICE_ID || - dev->pdev->device == TGL_H_DEVICE_ID || - dev->pdev->device == ADL_S_DEVICE_ID || - dev->pdev->device == ADL_P_DEVICE_ID); + return (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax || + dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_LP || + dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_H || + dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_S || + dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_P); } static const struct ishtp_hw_ops ish_hw_ops = { diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 56bd4f02f319..330916ed5bfd 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -24,29 +24,29 @@ #include "hw-ish.h" static const struct pci_device_id ish_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CHV_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Bx_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, APL_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CMP_H_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, EHL_Ax_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_LP_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_H_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_S_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_P_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_N_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, RPL_S_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MTL_P_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_H_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_S_DEVICE_ID)}, - {0, } + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CHV)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_BXT_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_BXT_Bx)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_APL_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_SPT_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CNL_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_GLK_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CNL_H)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ICL_MOBILE)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_SPT_H)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CML_LP)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CMP_H)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_EHL_Ax)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_TGL_LP)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_TGL_H)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_S)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_P)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ADL_N)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_RPL_S)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_MTL_P)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_H)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_S)}, + {} }; MODULE_DEVICE_TABLE(pci, ish_pci_tbl); @@ -105,19 +105,19 @@ static int ish_init(struct ishtp_device *dev) static const struct pci_device_id ish_invalid_pci_ids[] = { /* Mehlow platform special pci ids */ - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA309)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA30A)}, + {PCI_VDEVICE(INTEL, 0xA309)}, + {PCI_VDEVICE(INTEL, 0xA30A)}, {} }; static inline bool ish_should_enter_d0i3(struct pci_dev *pdev) { - return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID; + return !pm_suspend_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV; } static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) { - return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID; + return !pm_resume_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV; } /** @@ -189,7 +189,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) init_waitqueue_head(&ishtp->resume_wait); /* Enable PME for EHL */ - if (pdev->device == EHL_Ax_DEVICE_ID) + if (pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax) device_init_wakeup(dev, true); ret = ish_init(ishtp); @@ -222,7 +222,7 @@ static void ish_remove(struct pci_dev *pdev) */ static void ish_shutdown(struct pci_dev *pdev) { - if (pdev->device == EHL_Ax_DEVICE_ID) + if (pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax) pci_prepare_to_sleep(pdev); } -- cgit v1.2.3 From b06271e897cc28f1e6c668c432ab7f1078db1584 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Wed, 6 Mar 2024 00:56:38 +0000 Subject: HID: intel-ish-hid: ipc: Add Lunar Lake-M PCI device ID Add device ID of Lunar Lake-M into ishtp support list. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/hw-ish.h | 1 + drivers/hid/intel-ish-hid/ipc/pci-ish.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h index a4484f3ba2be..cdd80c653918 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h @@ -35,6 +35,7 @@ #define PCI_DEVICE_ID_INTEL_ISH_MTL_P 0x7E45 #define PCI_DEVICE_ID_INTEL_ISH_ARL_H 0x7745 #define PCI_DEVICE_ID_INTEL_ISH_ARL_S 0x7F78 +#define PCI_DEVICE_ID_INTEL_ISH_LNL_M 0xA845 #define REVISION_ID_CHT_A0 0x6 #define REVISION_ID_CHT_Ax_SI 0x0 diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 330916ed5bfd..e79d72f7db2a 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -46,6 +46,7 @@ static const struct pci_device_id ish_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_MTL_P)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_H)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_S)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_LNL_M)}, {} }; MODULE_DEVICE_TABLE(pci, ish_pci_tbl); -- cgit v1.2.3 From d030061f610e038bca66c4902ad0605bc1c85b89 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 6 Mar 2024 18:50:48 +0100 Subject: HID: google: hammer: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- drivers/hid/hid-google-hammer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index c6bdb9c4ef3e..25331695ae32 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -255,7 +255,7 @@ out: return retval; } -static int cbas_ec_remove(struct platform_device *pdev) +static void cbas_ec_remove(struct platform_device *pdev) { struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); @@ -266,7 +266,6 @@ static int cbas_ec_remove(struct platform_device *pdev) cbas_ec_set_input(NULL); mutex_unlock(&cbas_ec_reglock); - return 0; } static const struct acpi_device_id cbas_ec_acpi_ids[] = { @@ -285,7 +284,7 @@ MODULE_DEVICE_TABLE(of, cbas_ec_of_match); static struct platform_driver cbas_ec_driver = { .probe = cbas_ec_probe, - .remove = cbas_ec_remove, + .remove_new = cbas_ec_remove, .driver = { .name = "cbas_ec", .acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids), -- cgit v1.2.3 From afbc301cc04f986cc54e678981bee1ca41707cf6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 6 Mar 2024 18:50:49 +0100 Subject: HID: hid-sensor-custom: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Srinivas Pandruvada Reviewed-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-custom.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index d85398721659..de7287f3af61 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -1032,14 +1032,14 @@ err_remove_callback: return ret; } -static int hid_sensor_custom_remove(struct platform_device *pdev) +static void hid_sensor_custom_remove(struct platform_device *pdev) { struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev); struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; if (sensor_inst->custom_pdev) { platform_device_unregister(sensor_inst->custom_pdev); - return 0; + return; } hid_sensor_custom_dev_if_remove(sensor_inst); @@ -1047,8 +1047,6 @@ static int hid_sensor_custom_remove(struct platform_device *pdev) sysfs_remove_group(&sensor_inst->pdev->dev.kobj, &enable_sensor_attr_group); sensor_hub_remove_callback(hsdev, hsdev->usage); - - return 0; } static const struct platform_device_id hid_sensor_custom_ids[] = { @@ -1068,7 +1066,7 @@ static struct platform_driver hid_sensor_custom_platform_driver = { .name = KBUILD_MODNAME, }, .probe = hid_sensor_custom_probe, - .remove = hid_sensor_custom_remove, + .remove_new = hid_sensor_custom_remove, }; module_platform_driver(hid_sensor_custom_platform_driver); -- cgit v1.2.3 From 009faf979ea34f2e186e0e57c33a88ccd916e661 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 6 Mar 2024 18:50:50 +0100 Subject: HID: surface-hid: kbd: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Signed-off-by: Jiri Kosina --- drivers/hid/surface-hid/surface_kbd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c index 4fbce201db6a..8c0cbb2deb11 100644 --- a/drivers/hid/surface-hid/surface_kbd.c +++ b/drivers/hid/surface-hid/surface_kbd.c @@ -271,10 +271,9 @@ static int surface_kbd_probe(struct platform_device *pdev) return surface_hid_device_add(shid); } -static int surface_kbd_remove(struct platform_device *pdev) +static void surface_kbd_remove(struct platform_device *pdev) { surface_hid_device_destroy(platform_get_drvdata(pdev)); - return 0; } static const struct acpi_device_id surface_kbd_match[] = { @@ -285,7 +284,7 @@ MODULE_DEVICE_TABLE(acpi, surface_kbd_match); static struct platform_driver surface_kbd_driver = { .probe = surface_kbd_probe, - .remove = surface_kbd_remove, + .remove_new = surface_kbd_remove, .driver = { .name = "surface_keyboard", .acpi_match_table = surface_kbd_match, -- cgit v1.2.3 From 5307de63d71d0b2303a8c645493a36021bedd800 Mon Sep 17 00:00:00 2001 From: Martino Fontana Date: Mon, 18 Mar 2024 11:36:28 +0100 Subject: HID: nintendo: use ida for LED player id Previously, the leds pattern would just increment with every controller connected. This wouldn't take into consideration when controllers are disconnected. The same controller could be connected and disconnected with the pattern increasing player count each time. This patch changes it by using an ID allocator in order to assign the player id, the same way hid-playstation does. Signed-off-by: Martino Fontana Signed-off-by: Ryan McClelland Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index ab5953fc2436..ce88ac7617fd 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -569,6 +570,7 @@ static const enum led_brightness joycon_player_led_patterns[JC_NUM_LED_PATTERNS] struct joycon_ctlr { struct hid_device *hdev; struct input_dev *input; + u32 player_id; struct led_classdev leds[JC_NUM_LEDS]; /* player leds */ struct led_classdev home_led; enum joycon_ctlr_state ctlr_state; @@ -2261,7 +2263,8 @@ static int joycon_home_led_brightness_set(struct led_classdev *led, return ret; } -static DEFINE_SPINLOCK(joycon_input_num_spinlock); +static DEFINE_IDA(nintendo_player_id_allocator); + static int joycon_leds_create(struct joycon_ctlr *ctlr) { struct hid_device *hdev = ctlr->hdev; @@ -2272,20 +2275,19 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr) char *name; int ret; int i; - unsigned long flags; int player_led_pattern; - static int input_num; - - /* - * Set the player leds based on controller number - * Because there is no standard concept of "player number", the pattern - * number will simply increase by 1 every time a controller is connected. - */ - spin_lock_irqsave(&joycon_input_num_spinlock, flags); - player_led_pattern = input_num++ % JC_NUM_LED_PATTERNS; - spin_unlock_irqrestore(&joycon_input_num_spinlock, flags); /* configure the player LEDs */ + ctlr->player_id = U32_MAX; + ret = ida_alloc(&nintendo_player_id_allocator, GFP_KERNEL); + if (ret < 0) { + hid_warn(hdev, "Failed to allocate player ID, skipping; ret=%d\n", ret); + goto home_led; + } + ctlr->player_id = ret; + player_led_pattern = ret % JC_NUM_LED_PATTERNS; + hid_info(ctlr->hdev, "assigned player %d led pattern", player_led_pattern + 1); + for (i = 0; i < JC_NUM_LEDS; i++) { name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s", d_name, @@ -2767,6 +2769,7 @@ static void nintendo_hid_remove(struct hid_device *hdev) spin_unlock_irqrestore(&ctlr->lock, flags); destroy_workqueue(ctlr->rumble_queue); + ida_free(&nintendo_player_id_allocator, ctlr->player_id); hid_hw_close(hdev); hid_hw_stop(hdev); @@ -2824,7 +2827,19 @@ static struct hid_driver nintendo_hid_driver = { .resume = nintendo_hid_resume, #endif }; -module_hid_driver(nintendo_hid_driver); +static int __init nintendo_init(void) +{ + return hid_register_driver(&nintendo_hid_driver); +} + +static void __exit nintendo_exit(void) +{ + hid_unregister_driver(&nintendo_hid_driver); + ida_destroy(&nintendo_player_id_allocator); +} + +module_init(nintendo_init); +module_exit(nintendo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ryan McClelland "); -- cgit v1.2.3 From 266c990debad2f9589c7a412e897a8e312b09766 Mon Sep 17 00:00:00 2001 From: Ivan Gorinov Date: Fri, 16 Feb 2024 21:54:47 -0800 Subject: HID: Add WinWing Orion2 throttle support WinWing Orion2 throttle works with Linux out of box, but the kernel sees only 16 of 47 buttons on the throttle base. This module enables all buttons, and also adds LED controls. Button numbers 0 .. 63 on Orion2 are reserved for throttle grip; the throttle base buttons have numbers 64 .. 110. Linux kernel HID subsystem only supports up to 80 buttons. Remap throttle base buttons to numbers 32 .. 78, reserving only numbers 0 .. 31 for buttons on the grip handle. Changes since v2: - Fixed automatic line wraps added by mail client Changes since v1: - Fixed formatting of descriptor byte array; - Using product codes of Winwing grips in config. Signed-off-by: Ivan Gorinov Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 16 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-winwing.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/hid/hid-winwing.c (limited to 'drivers/hid') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4c682c650704..08446c89eff6 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1236,6 +1236,22 @@ config HID_WIIMOTE To compile this driver as a module, choose M here: the module will be called hid-wiimote. +config HID_WINWING + tristate "WinWing Orion2 throttle support" + depends on USB_HID + depends on NEW_LEDS + depends on LEDS_CLASS + help + Support for WinWing Orion2 throttle base with the following grips: + + * TGRIP-16EX + * TGRIP-18 + + This driver enables all buttons and switches on the throttle base. + + To compile this driver as a module, choose M here: the + module will be called hid-winwing. + config HID_XINMO tristate "Xin-Mo non-fully compliant devices" help diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 082a728eac60..ce71b53ea6c5 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -150,6 +150,7 @@ wacom-objs := wacom_wac.o wacom_sys.o obj-$(CONFIG_HID_WACOM) += wacom.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o +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 diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c new file mode 100644 index 000000000000..d895c82a541d --- /dev/null +++ b/drivers/hid/hid-winwing.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * HID driver for WinWing Orion 2 throttle + * + * Copyright (c) 2023 Ivan Gorinov + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_REPORT 16 + +struct winwing_led { + struct led_classdev cdev; + struct hid_device *hdev; + int number; +}; + +struct winwing_led_info { + int number; + int max_brightness; + const char *led_name; +}; + +static struct winwing_led_info led_info[3] = { + { 0, 255, "backlight" }, + { 1, 1, "a-a" }, + { 2, 1, "a-g" }, +}; + +struct winwing_drv_data { + struct hid_device *hdev; + __u8 *report_buf; + struct mutex lock; + unsigned int num_leds; + struct winwing_led leds[]; +}; + +static int winwing_led_write(struct led_classdev *cdev, + enum led_brightness br) +{ + struct winwing_led *led = (struct winwing_led *) cdev; + struct winwing_drv_data *data = hid_get_drvdata(led->hdev); + __u8 *buf = data->report_buf; + int ret; + + mutex_lock(&data->lock); + + buf[0] = 0x02; + buf[1] = 0x60; + buf[2] = 0xbe; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x03; + buf[6] = 0x49; + buf[7] = led->number; + buf[8] = br; + buf[9] = 0x00; + buf[10] = 0; + buf[11] = 0; + buf[12] = 0; + buf[13] = 0; + + ret = hid_hw_output_report(led->hdev, buf, 14); + + mutex_unlock(&data->lock); + + return ret; +} + +static int winwing_init_led(struct hid_device *hdev, + struct input_dev *input) +{ + struct winwing_drv_data *data; + struct winwing_led *led; + int ret; + int i; + + size_t data_size = struct_size(data, leds, 3); + + data = devm_kzalloc(&hdev->dev, data_size, GFP_KERNEL); + + if (!data) + return -ENOMEM; + + data->report_buf = devm_kmalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL); + + if (!data->report_buf) + return -ENOMEM; + + for (i = 0; i < 3; i += 1) { + struct winwing_led_info *info = &led_info[i]; + + led = &data->leds[i]; + led->hdev = hdev; + led->number = info->number; + led->cdev.max_brightness = info->max_brightness; + led->cdev.brightness_set_blocking = winwing_led_write; + led->cdev.flags = LED_HW_PLUGGABLE; + led->cdev.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "%s::%s", + dev_name(&input->dev), + info->led_name); + + ret = devm_led_classdev_register(&hdev->dev, &led->cdev); + if (ret) + return ret; + } + + hid_set_drvdata(hdev, data); + + return ret; +} + +static int winwing_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + unsigned int minor; + int ret; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + minor = ((struct hidraw *) hdev->hidraw)->minor; + + return 0; +} + +static int winwing_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) +{ + int ret; + + ret = winwing_init_led(hdev, hidinput->input); + + if (ret) + hid_err(hdev, "led init failed\n"); + + return ret; +} + +static __u8 original_rdesc_buttons[] = { + 0x05, 0x09, 0x19, 0x01, 0x29, 0x6F, + 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, + 0x45, 0x01, 0x75, 0x01, 0x95, 0x6F, + 0x81, 0x02, 0x75, 0x01, 0x95, 0x01, + 0x81, 0x01 +}; + +/* + * HID report descriptor shows 111 buttons, which exceeds maximum + * number of buttons (80) supported by Linux kernel HID subsystem. + * + * This module skips numbers 32-63, unused on some throttle grips. + */ + +static __u8 *winwing_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + int sig_length = sizeof(original_rdesc_buttons); + int unused_button_numbers = 32; + + if (*rsize < 34) + return rdesc; + + if (memcmp(rdesc + 8, original_rdesc_buttons, sig_length) == 0) { + + /* Usage Maximum */ + rdesc[13] -= unused_button_numbers; + + /* Report Count for buttons */ + rdesc[25] -= unused_button_numbers; + + /* Report Count for padding [HID1_11, 6.2.2.9] */ + rdesc[31] += unused_button_numbers; + + hid_info(hdev, "winwing descriptor fixed\n"); + } + + return rdesc; +} + +static int winwing_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *raw_data, int size) +{ + if (size >= 15) { + /* Skip buttons 32 .. 63 */ + memmove(raw_data + 5, raw_data + 9, 6); + + /* Clear the padding */ + memset(raw_data + 11, 0, 4); + } + + return 0; +} + +static const struct hid_device_id winwing_devices[] = { + { HID_USB_DEVICE(0x4098, 0xbe62) }, /* TGRIP-18 */ + { HID_USB_DEVICE(0x4098, 0xbe68) }, /* TGRIP-16EX */ + {} +}; + +MODULE_DEVICE_TABLE(hid, winwing_devices); + +static struct hid_driver winwing_driver = { + .name = "winwing", + .id_table = winwing_devices, + .probe = winwing_probe, + .input_configured = winwing_input_configured, + .report_fixup = winwing_report_fixup, + .raw_event = winwing_raw_event, +}; +module_hid_driver(winwing_driver); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 28ba6011f5dfd337e61e9c5618824115c63be66a Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Sat, 16 Mar 2024 01:57:29 +0900 Subject: HID: nintendo: Don't fail on setting baud rate Some third-party controllers can't change the baud rate. We can still use the gamepad as-is, so let's do that. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index ce88ac7617fd..e311b092e758 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -2503,8 +2503,11 @@ static int joycon_init(struct hid_device *hdev) /* set baudrate for improved latency */ ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ); if (ret) { - hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret); - goto out_unlock; + /* + * We can function with the default baudrate. + * Provide a warning, and continue on. + */ + hid_warn(hdev, "Failed to set baudrate (ret=%d), continuing anyway\n", ret); } /* handshake */ ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ); -- cgit v1.2.3 From 247481b893e34805bfd94fdc34a34faa3bdec2de Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 19 Mar 2024 13:45:24 +0800 Subject: HID: hid-picolcd*: Convert sprintf() family to sysfs_emit() family MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). sprintf() and scnprintf() will be converted as well if they have. Generally, this patch is generated by make coccicheck M= MODE=patch \ COCCI=scripts/coccinelle/api/device_attr_show.cocci No functional change intended CC: Christophe JAILLET CC: "Bruno Prémont" CC: Jiri Kosina CC: Benjamin Tissoires CC: linux-input@vger.kernel.org Signed-off-by: Li Zhijian Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd_core.c | 6 +++--- drivers/hid/hid-picolcd_fb.c | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index bbda231a7ce3..fa46fb6eab3f 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c @@ -256,9 +256,9 @@ static ssize_t picolcd_operation_mode_show(struct device *dev, struct picolcd_data *data = dev_get_drvdata(dev); if (data->status & PICOLCD_BOOTLOADER) - return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n"); + return sysfs_emit(buf, "[bootloader] lcd\n"); else - return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n"); + return sysfs_emit(buf, "bootloader [lcd]\n"); } static ssize_t picolcd_operation_mode_store(struct device *dev, @@ -301,7 +301,7 @@ static ssize_t picolcd_operation_mode_delay_show(struct device *dev, { struct picolcd_data *data = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); + return sysfs_emit(buf, "%hu\n", data->opmode_delay); } static ssize_t picolcd_operation_mode_delay_store(struct device *dev, diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index d7dddd99d325..063f9c01d2f7 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -421,12 +421,10 @@ static ssize_t picolcd_fb_update_rate_show(struct device *dev, size_t ret = 0; for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) - if (ret >= PAGE_SIZE) - break; - else if (i == fb_update_rate) - ret += scnprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); + if (i == fb_update_rate) + ret += sysfs_emit_at(buf, ret, "[%u] ", i); else - ret += scnprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); + ret += sysfs_emit_at(buf, ret, "%u ", i); if (ret > 0) buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; return ret; -- cgit v1.2.3 From 460560fda31b8d22b7dac0f69965e3626536b5bb Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 19 Mar 2024 13:45:25 +0800 Subject: HID: hid-sensor-custom: Convert sprintf() family to sysfs_emit() family Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). sprintf() and scnprintf() will be converted as well if they have. Generally, this patch is generated by make coccicheck M= MODE=patch \ COCCI=scripts/coccinelle/api/device_attr_show.cocci No functional change intended CC: Jiri Kosina CC: Jonathan Cameron CC: Srinivas Pandruvada CC: Benjamin Tissoires CC: linux-input@vger.kernel.org CC: linux-iio@vger.kernel.org Reviewed-by: Jonathan Cameron Signed-off-by: Li Zhijian Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-custom.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index d85398721659..ac214777d7d9 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -155,7 +155,7 @@ static ssize_t enable_sensor_show(struct device *dev, { struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", sensor_inst->enable); + return sysfs_emit(buf, "%d\n", sensor_inst->enable); } static int set_power_report_state(struct hid_sensor_custom *sensor_inst, @@ -372,14 +372,13 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr, sizeof(struct hid_custom_usage_desc), usage_id_cmp); if (usage_desc) - return snprintf(buf, PAGE_SIZE, "%s\n", - usage_desc->desc); + return sysfs_emit(buf, "%s\n", usage_desc->desc); else - return sprintf(buf, "not-specified\n"); + return sysfs_emit(buf, "not-specified\n"); } else return -EINVAL; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } static ssize_t store_value(struct device *dev, struct device_attribute *attr, -- cgit v1.2.3 From 0336d4e997a0c384b44026935f0e19ad71d27b06 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 19 Mar 2024 13:45:26 +0800 Subject: HID: roccat: Convert sprintf() family to sysfs_emit() family Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). sprintf() and scnprintf() will be converted as well if they have. Generally, this patch is generated by make coccicheck M= MODE=patch \ COCCI=scripts/coccinelle/api/device_attr_show.cocci No functional change intended CC: Stefan Achatz CC: Jiri Kosina CC: Benjamin Tissoires CC: linux-input@vger.kernel.org Signed-off-by: Li Zhijian Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-isku.c | 2 +- drivers/hid/hid-roccat-kone.c | 12 ++++++------ drivers/hid/hid-roccat-koneplus.c | 4 ++-- drivers/hid/hid-roccat-kovaplus.c | 10 +++++----- drivers/hid/hid-roccat-pyra.c | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index 458060403397..0cd6208fb371 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c @@ -61,7 +61,7 @@ static ssize_t isku_sysfs_show_actual_profile(struct device *dev, { struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", isku->actual_profile); + return sysfs_emit(buf, "%d\n", isku->actual_profile); } static ssize_t isku_sysfs_set_actual_profile(struct device *dev, diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 00a1abc7e839..3f8f459edcf3 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -400,7 +400,7 @@ static ssize_t kone_sysfs_show_actual_profile(struct device *dev, { struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile); + return sysfs_emit(buf, "%d\n", kone->actual_profile); } static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL); @@ -409,7 +409,7 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev, { struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi); + return sysfs_emit(buf, "%d\n", kone->actual_dpi); } static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL); @@ -432,7 +432,7 @@ static ssize_t kone_sysfs_show_weight(struct device *dev, if (retval) return retval; - return snprintf(buf, PAGE_SIZE, "%d\n", weight); + return sysfs_emit(buf, "%d\n", weight); } static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL); @@ -441,7 +441,7 @@ static ssize_t kone_sysfs_show_firmware_version(struct device *dev, { struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version); + return sysfs_emit(buf, "%d\n", kone->firmware_version); } static DEVICE_ATTR(firmware_version, 0440, kone_sysfs_show_firmware_version, NULL); @@ -451,7 +451,7 @@ static ssize_t kone_sysfs_show_tcu(struct device *dev, { struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu); + return sysfs_emit(buf, "%d\n", kone->settings.tcu); } static int kone_tcu_command(struct usb_device *usb_dev, int number) @@ -553,7 +553,7 @@ static ssize_t kone_sysfs_show_startup_profile(struct device *dev, { struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile); + return sysfs_emit(buf, "%d\n", kone->settings.startup_profile); } static ssize_t kone_sysfs_set_startup_profile(struct device *dev, diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 22b895436a7c..8ccb3b14a1a9 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -242,7 +242,7 @@ static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev, { struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile); + return sysfs_emit(buf, "%d\n", koneplus->actual_profile); } static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, @@ -309,7 +309,7 @@ static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev, &info, KONEPLUS_SIZE_INFO); mutex_unlock(&koneplus->koneplus_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version); + return sysfs_emit(buf, "%d\n", info.firmware_version); } static DEVICE_ATTR(firmware_version, 0440, koneplus_sysfs_show_firmware_version, NULL); diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 86af538c10d6..748d4d7cb2fc 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -272,7 +272,7 @@ static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev, { struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile); + return sysfs_emit(buf, "%d\n", kovaplus->actual_profile); } static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, @@ -325,7 +325,7 @@ static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev, { struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi); + return sysfs_emit(buf, "%d\n", kovaplus->actual_cpi); } static DEVICE_ATTR(actual_cpi, 0440, kovaplus_sysfs_show_actual_cpi, NULL); @@ -334,7 +334,7 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev, { struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity); + return sysfs_emit(buf, "%d\n", kovaplus->actual_x_sensitivity); } static DEVICE_ATTR(actual_sensitivity_x, 0440, kovaplus_sysfs_show_actual_sensitivity_x, NULL); @@ -344,7 +344,7 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev, { struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity); + return sysfs_emit(buf, "%d\n", kovaplus->actual_y_sensitivity); } static DEVICE_ATTR(actual_sensitivity_y, 0440, kovaplus_sysfs_show_actual_sensitivity_y, NULL); @@ -365,7 +365,7 @@ static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev, &info, KOVAPLUS_SIZE_INFO); mutex_unlock(&kovaplus->kovaplus_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version); + return sysfs_emit(buf, "%d\n", info.firmware_version); } static DEVICE_ATTR(firmware_version, 0440, kovaplus_sysfs_show_firmware_version, NULL); diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 5663b9cd9c69..eeb3d38cd805 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -283,7 +283,7 @@ static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev, { struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi); + return sysfs_emit(buf, "%d\n", pyra->actual_cpi); } static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL); @@ -300,7 +300,7 @@ static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, &settings, PYRA_SIZE_SETTINGS); mutex_unlock(&pyra->pyra_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", settings.startup_profile); + return sysfs_emit(buf, "%d\n", settings.startup_profile); } static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL); static DEVICE_ATTR(startup_profile, 0440, pyra_sysfs_show_actual_profile, NULL); @@ -321,7 +321,7 @@ static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, &info, PYRA_SIZE_INFO); mutex_unlock(&pyra->pyra_lock); - return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version); + return sysfs_emit(buf, "%d\n", info.firmware_version); } static DEVICE_ATTR(firmware_version, 0440, pyra_sysfs_show_firmware_version, NULL); -- cgit v1.2.3 From 209eb1f30e9bb305c92f0a53ce6f6ddf5a9f4060 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 19 Mar 2024 13:45:27 +0800 Subject: HID: corsair,lenovo: Convert sprintf() family to sysfs_emit() family Per filesystems/sysfs.rst, show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. coccinelle complains that there are still a couple of functions that use snprintf(). Convert them to sysfs_emit(). sprintf() and scnprintf() will be converted as well if they have. Generally, this patch is generated by make coccicheck M= MODE=patch \ COCCI=scripts/coccinelle/api/device_attr_show.cocci No functional change intended CC: Jiri Kosina CC: Benjamin Tissoires CC: linux-input@vger.kernel.org Signed-off-by: Li Zhijian Signed-off-by: Jiri Kosina --- drivers/hid/hid-corsair.c | 4 ++-- drivers/hid/hid-lenovo.c | 23 ++++++++++------------- 2 files changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c index 8c895c820b67..702f50e9841d 100644 --- a/drivers/hid/hid-corsair.c +++ b/drivers/hid/hid-corsair.c @@ -298,7 +298,7 @@ static ssize_t k90_show_macro_mode(struct device *dev, goto out; } - ret = snprintf(buf, PAGE_SIZE, "%s\n", macro_mode); + ret = sysfs_emit(buf, "%s\n", macro_mode); out: kfree(data); @@ -367,7 +367,7 @@ static ssize_t k90_show_current_profile(struct device *dev, goto out; } - ret = snprintf(buf, PAGE_SIZE, "%d\n", current_profile); + ret = sysfs_emit(buf, "%d\n", current_profile); out: kfree(data); diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index f86c1ea83a03..e6b2ae68b8fb 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -555,7 +555,7 @@ static ssize_t attr_fn_lock_show(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", data->fn_lock); + return sysfs_emit(buf, "%u\n", data->fn_lock); } static ssize_t attr_fn_lock_store(struct device *dev, @@ -599,8 +599,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", - cptkbd_data->sensitivity); + return sysfs_emit(buf, "%u\n", cptkbd_data->sensitivity); } static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, @@ -628,8 +627,8 @@ static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", - cptkbd_data->middleclick_workaround_cptkbd); + return sysfs_emit(buf, "%u\n", + cptkbd_data->middleclick_workaround_cptkbd); } static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev, @@ -809,7 +808,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); + return sysfs_emit(buf, "%u\n", data_pointer->press_to_select); } static ssize_t attr_press_to_select_store_tpkbd(struct device *dev, @@ -839,7 +838,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); + return sysfs_emit(buf, "%u\n", data_pointer->dragging); } static ssize_t attr_dragging_store_tpkbd(struct device *dev, @@ -869,7 +868,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); + return sysfs_emit(buf, "%u\n", data_pointer->release_to_select); } static ssize_t attr_release_to_select_store_tpkbd(struct device *dev, @@ -899,7 +898,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); + return sysfs_emit(buf, "%u\n", data_pointer->select_right); } static ssize_t attr_select_right_store_tpkbd(struct device *dev, @@ -929,8 +928,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", - data_pointer->sensitivity); + return sysfs_emit(buf, "%u\n", data_pointer->sensitivity); } static ssize_t attr_sensitivity_store_tpkbd(struct device *dev, @@ -958,8 +956,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev, struct hid_device *hdev = to_hid_device(dev); struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", - data_pointer->press_speed); + return sysfs_emit(buf, "%u\n", data_pointer->press_speed); } static ssize_t attr_press_speed_store_tpkbd(struct device *dev, -- cgit v1.2.3 From 5465d9f5c6df6c10ee7f9fe03c33a81554e6d0c1 Mon Sep 17 00:00:00 2001 From: Thomas Kuehne Date: Mon, 25 Mar 2024 01:23:15 +0000 Subject: HID: hid-debug: add missing evdev and HID codes Hid-debug's rdesc output for a game controller contained a few question marks and numeric IDs instead of the expected descriptive names. This happens because: 1) the mapping data is missing event codes defined in input-event-codes.h 2) HID usages aren't up to date 3) hid_resolv_usage fails to account for the sensor pages' modifiers Add missing event codes and update HID to HUT 1.5. Signed-off-by: Thomas Kuehne Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 3400 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 2960 insertions(+), 440 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 7dd83ec74f8a..add353a17853 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -37,437 +37,2808 @@ struct hid_usage_entry { }; static const struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-PadUp"}, - {0, 0x91, "D-PadDown"}, - {0, 0x92, "D-PadRight"}, - {0, 0x93, "D-PadLeft"}, - { 2, 0, "Simulation" }, - {0, 0xb0, "Aileron"}, - {0, 0xb1, "AileronTrim"}, - {0, 0xb2, "Anti-Torque"}, - {0, 0xb3, "Autopilot"}, - {0, 0xb4, "Chaff"}, - {0, 0xb5, "Collective"}, - {0, 0xb6, "DiveBrake"}, - {0, 0xb7, "ElectronicCountermeasures"}, - {0, 0xb8, "Elevator"}, - {0, 0xb9, "ElevatorTrim"}, - {0, 0xba, "Rudder"}, - {0, 0xbb, "Throttle"}, - {0, 0xbc, "FlightCommunications"}, - {0, 0xbd, "FlareRelease"}, - {0, 0xbe, "LandingGear"}, - {0, 0xbf, "ToeBrake"}, - { 6, 0, "GenericDeviceControls" }, - {0, 0x20, "BatteryStrength" }, - {0, 0x21, "WirelessChannel" }, - {0, 0x22, "WirelessID" }, - {0, 0x23, "DiscoverWirelessControl" }, - {0, 0x24, "SecurityCodeCharacterEntered" }, - {0, 0x25, "SecurityCodeCharactedErased" }, - {0, 0x26, "SecurityCodeCleared" }, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - {0, 0x01, "NumLock"}, - {0, 0x02, "CapsLock"}, - {0, 0x03, "ScrollLock"}, - {0, 0x04, "Compose"}, - {0, 0x05, "Kana"}, - {0, 0x4b, "GenericIndicator"}, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Consumer" }, - {0, 0x003, "ProgrammableButtons"}, - {0, 0x238, "HorizontalWheel"}, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x0e, "DeviceConfiguration"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x23, "DeviceSettings"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x38, "Transducer Index"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3B, "Battery Strength"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - {0, 0x47, "Confidence"}, - {0, 0x48, "Width"}, - {0, 0x49, "Height"}, - {0, 0x51, "ContactID"}, - {0, 0x52, "InputMode"}, - {0, 0x53, "DeviceIndex"}, - {0, 0x54, "ContactCount"}, - {0, 0x55, "ContactMaximumNumber"}, - {0, 0x59, "ButtonType"}, - {0, 0x5A, "SecondaryBarrelSwitch"}, - {0, 0x5B, "TransducerSerialNumber"}, - {0, 0x5C, "Preferred Color"}, - {0, 0x5D, "Preferred Color is Locked"}, - {0, 0x5E, "Preferred Line Width"}, - {0, 0x5F, "Preferred Line Width is Locked"}, - {0, 0x6e, "TransducerSerialNumber2"}, - {0, 0x70, "Preferred Line Style"}, - {0, 0x71, "Preferred Line Style is Locked"}, - {0, 0x72, "Ink"}, - {0, 0x73, "Pencil"}, - {0, 0x74, "Highlighter"}, - {0, 0x75, "Chisel Marker"}, - {0, 0x76, "Brush"}, - {0, 0x77, "No Preference"}, - {0, 0x80, "Digitizer Diagnostic"}, - {0, 0x81, "Digitizer Error"}, - {0, 0x82, "Err Normal Status"}, - {0, 0x83, "Err Transducers Exceeded"}, - {0, 0x84, "Err Full Trans Features Unavailable"}, - {0, 0x85, "Err Charge Low"}, - {0, 0x90, "Transducer Software Info"}, - {0, 0x91, "Transducer Vendor Id"}, - {0, 0x92, "Transducer Product Id"}, - {0, 0x93, "Device Supported Protocols"}, - {0, 0x94, "Transducer Supported Protocols"}, - {0, 0x95, "No Protocol"}, - {0, 0x96, "Wacom AES Protocol"}, - {0, 0x97, "USI Protocol"}, - {0, 0x98, "Microsoft Pen Protocol"}, - {0, 0xA0, "Supported Report Rates"}, - {0, 0xA1, "Report Rate"}, - {0, 0xA2, "Transducer Connected"}, - {0, 0xA3, "Switch Disabled"}, - {0, 0xA4, "Switch Unimplemented"}, - {0, 0xA5, "Transducer Switches"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0x20, 0, "Sensor" }, - { 0x20, 0x01, "Sensor" }, - { 0x20, 0x10, "Biometric" }, - { 0x20, 0x11, "BiometricHumanPresence" }, - { 0x20, 0x12, "BiometricHumanProximity" }, - { 0x20, 0x13, "BiometricHumanTouch" }, - { 0x20, 0x20, "Electrical" }, - { 0x20, 0x21, "ElectricalCapacitance" }, - { 0x20, 0x22, "ElectricalCurrent" }, - { 0x20, 0x23, "ElectricalPower" }, - { 0x20, 0x24, "ElectricalInductance" }, - { 0x20, 0x25, "ElectricalResistance" }, - { 0x20, 0x26, "ElectricalVoltage" }, - { 0x20, 0x27, "ElectricalPoteniometer" }, - { 0x20, 0x28, "ElectricalFrequency" }, - { 0x20, 0x29, "ElectricalPeriod" }, - { 0x20, 0x30, "Environmental" }, - { 0x20, 0x31, "EnvironmentalAtmosphericPressure" }, - { 0x20, 0x32, "EnvironmentalHumidity" }, - { 0x20, 0x33, "EnvironmentalTemperature" }, - { 0x20, 0x34, "EnvironmentalWindDirection" }, - { 0x20, 0x35, "EnvironmentalWindSpeed" }, - { 0x20, 0x40, "Light" }, - { 0x20, 0x41, "LightAmbientLight" }, - { 0x20, 0x42, "LightConsumerInfrared" }, - { 0x20, 0x50, "Location" }, - { 0x20, 0x51, "LocationBroadcast" }, - { 0x20, 0x52, "LocationDeadReckoning" }, - { 0x20, 0x53, "LocationGPS" }, - { 0x20, 0x54, "LocationLookup" }, - { 0x20, 0x55, "LocationOther" }, - { 0x20, 0x56, "LocationStatic" }, - { 0x20, 0x57, "LocationTriangulation" }, - { 0x20, 0x60, "Mechanical" }, - { 0x20, 0x61, "MechanicalBooleanSwitch" }, - { 0x20, 0x62, "MechanicalBooleanSwitchArray" }, - { 0x20, 0x63, "MechanicalMultivalueSwitch" }, - { 0x20, 0x64, "MechanicalForce" }, - { 0x20, 0x65, "MechanicalPressure" }, - { 0x20, 0x66, "MechanicalStrain" }, - { 0x20, 0x67, "MechanicalWeight" }, - { 0x20, 0x68, "MechanicalHapticVibrator" }, - { 0x20, 0x69, "MechanicalHallEffectSwitch" }, - { 0x20, 0x70, "Motion" }, - { 0x20, 0x71, "MotionAccelerometer1D" }, - { 0x20, 0x72, "MotionAccelerometer2D" }, - { 0x20, 0x73, "MotionAccelerometer3D" }, - { 0x20, 0x74, "MotionGyrometer1D" }, - { 0x20, 0x75, "MotionGyrometer2D" }, - { 0x20, 0x76, "MotionGyrometer3D" }, - { 0x20, 0x77, "MotionMotionDetector" }, - { 0x20, 0x78, "MotionSpeedometer" }, - { 0x20, 0x79, "MotionAccelerometer" }, - { 0x20, 0x7A, "MotionGyrometer" }, - { 0x20, 0x80, "Orientation" }, - { 0x20, 0x81, "OrientationCompass1D" }, - { 0x20, 0x82, "OrientationCompass2D" }, - { 0x20, 0x83, "OrientationCompass3D" }, - { 0x20, 0x84, "OrientationInclinometer1D" }, - { 0x20, 0x85, "OrientationInclinometer2D" }, - { 0x20, 0x86, "OrientationInclinometer3D" }, - { 0x20, 0x87, "OrientationDistance1D" }, - { 0x20, 0x88, "OrientationDistance2D" }, - { 0x20, 0x89, "OrientationDistance3D" }, - { 0x20, 0x8A, "OrientationDeviceOrientation" }, - { 0x20, 0x8B, "OrientationCompass" }, - { 0x20, 0x8C, "OrientationInclinometer" }, - { 0x20, 0x8D, "OrientationDistance" }, - { 0x20, 0x90, "Scanner" }, - { 0x20, 0x91, "ScannerBarcode" }, - { 0x20, 0x91, "ScannerRFID" }, - { 0x20, 0x91, "ScannerNFC" }, - { 0x20, 0xA0, "Time" }, - { 0x20, 0xA1, "TimeAlarmTimer" }, - { 0x20, 0xA2, "TimeRealTimeClock" }, - { 0x20, 0xE0, "Other" }, - { 0x20, 0xE1, "OtherCustom" }, - { 0x20, 0xE2, "OtherGeneric" }, - { 0x20, 0xE3, "OtherGenericEnumerator" }, - { 0x84, 0, "Power Device" }, - { 0x84, 0x02, "PresentStatus" }, - { 0x84, 0x03, "ChangeStatus" }, - { 0x84, 0x04, "UPS" }, - { 0x84, 0x05, "PowerSupply" }, - { 0x84, 0x10, "BatterySystem" }, - { 0x84, 0x11, "BatterySystemID" }, - { 0x84, 0x12, "Battery" }, - { 0x84, 0x13, "BatteryID" }, - { 0x84, 0x14, "Charger" }, - { 0x84, 0x15, "ChargerID" }, - { 0x84, 0x16, "PowerConverter" }, - { 0x84, 0x17, "PowerConverterID" }, - { 0x84, 0x18, "OutletSystem" }, - { 0x84, 0x19, "OutletSystemID" }, - { 0x84, 0x1a, "Input" }, - { 0x84, 0x1b, "InputID" }, - { 0x84, 0x1c, "Output" }, - { 0x84, 0x1d, "OutputID" }, - { 0x84, 0x1e, "Flow" }, - { 0x84, 0x1f, "FlowID" }, - { 0x84, 0x20, "Outlet" }, - { 0x84, 0x21, "OutletID" }, - { 0x84, 0x22, "Gang" }, - { 0x84, 0x24, "PowerSummary" }, - { 0x84, 0x25, "PowerSummaryID" }, - { 0x84, 0x30, "Voltage" }, - { 0x84, 0x31, "Current" }, - { 0x84, 0x32, "Frequency" }, - { 0x84, 0x33, "ApparentPower" }, - { 0x84, 0x35, "PercentLoad" }, - { 0x84, 0x40, "ConfigVoltage" }, - { 0x84, 0x41, "ConfigCurrent" }, - { 0x84, 0x43, "ConfigApparentPower" }, - { 0x84, 0x53, "LowVoltageTransfer" }, - { 0x84, 0x54, "HighVoltageTransfer" }, - { 0x84, 0x56, "DelayBeforeStartup" }, - { 0x84, 0x57, "DelayBeforeShutdown" }, - { 0x84, 0x58, "Test" }, - { 0x84, 0x5a, "AudibleAlarmControl" }, - { 0x84, 0x60, "Present" }, - { 0x84, 0x61, "Good" }, - { 0x84, 0x62, "InternalFailure" }, - { 0x84, 0x65, "Overload" }, - { 0x84, 0x66, "OverCharged" }, - { 0x84, 0x67, "OverTemperature" }, - { 0x84, 0x68, "ShutdownRequested" }, - { 0x84, 0x69, "ShutdownImminent" }, - { 0x84, 0x6b, "SwitchOn/Off" }, - { 0x84, 0x6c, "Switchable" }, - { 0x84, 0x6d, "Used" }, - { 0x84, 0x6e, "Boost" }, - { 0x84, 0x73, "CommunicationLost" }, - { 0x84, 0xfd, "iManufacturer" }, - { 0x84, 0xfe, "iProduct" }, - { 0x84, 0xff, "iSerialNumber" }, - { 0x85, 0, "Battery System" }, - { 0x85, 0x01, "SMBBatteryMode" }, - { 0x85, 0x02, "SMBBatteryStatus" }, - { 0x85, 0x03, "SMBAlarmWarning" }, - { 0x85, 0x04, "SMBChargerMode" }, - { 0x85, 0x05, "SMBChargerStatus" }, - { 0x85, 0x06, "SMBChargerSpecInfo" }, - { 0x85, 0x07, "SMBSelectorState" }, - { 0x85, 0x08, "SMBSelectorPresets" }, - { 0x85, 0x09, "SMBSelectorInfo" }, - { 0x85, 0x29, "RemainingCapacityLimit" }, - { 0x85, 0x2c, "CapacityMode" }, - { 0x85, 0x42, "BelowRemainingCapacityLimit" }, - { 0x85, 0x44, "Charging" }, - { 0x85, 0x45, "Discharging" }, - { 0x85, 0x4b, "NeedReplacement" }, - { 0x85, 0x65, "AbsoluteStateOfCharge" }, - { 0x85, 0x66, "RemainingCapacity" }, - { 0x85, 0x68, "RunTimeToEmpty" }, - { 0x85, 0x6a, "AverageTimeToFull" }, - { 0x85, 0x83, "DesignCapacity" }, - { 0x85, 0x85, "ManufacturerDate" }, - { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargeable" }, - { 0x85, 0x8f, "iOEMInformation" }, - { 0x85, 0x8d, "CapacityGranularity1" }, - { 0x85, 0xd0, "ACPresent" }, - /* pages 0xff00 to 0xffff are vendor-specific */ - { 0xffff, 0, "Vendor-specific-FF" }, - { 0, 0, NULL } + { 0x00, 0, "Undefined" }, + { 0x01, 0, "GenericDesktop" }, + { 0x01, 0x0001, "Pointer" }, + { 0x01, 0x0002, "Mouse" }, + { 0x01, 0x0004, "Joystick" }, + { 0x01, 0x0005, "Gamepad" }, + { 0x01, 0x0006, "Keyboard" }, + { 0x01, 0x0007, "Keypad" }, + { 0x01, 0x0008, "MultiaxisController" }, + { 0x01, 0x0009, "TabletPCSystemControls" }, + { 0x01, 0x000a, "WaterCoolingDevice" }, + { 0x01, 0x000b, "ComputerChassisDevice" }, + { 0x01, 0x000c, "WirelessRadioControls" }, + { 0x01, 0x000d, "PortableDeviceControl" }, + { 0x01, 0x000e, "SystemMultiAxisController" }, + { 0x01, 0x000f, "SpatialController" }, + { 0x01, 0x0010, "AssistiveControl" }, + { 0x01, 0x0011, "DeviceDock" }, + { 0x01, 0x0012, "DockableDevice" }, + { 0x01, 0x0013, "CallStateManagementControl" }, + { 0x01, 0x0030, "X" }, + { 0x01, 0x0031, "Y" }, + { 0x01, 0x0032, "Z" }, + { 0x01, 0x0033, "Rx" }, + { 0x01, 0x0034, "Ry" }, + { 0x01, 0x0035, "Rz" }, + { 0x01, 0x0036, "Slider" }, + { 0x01, 0x0037, "Dial" }, + { 0x01, 0x0038, "Wheel" }, + { 0x01, 0x0039, "HatSwitch" }, + { 0x01, 0x003a, "CountedBuffer" }, + { 0x01, 0x003b, "ByteCount" }, + { 0x01, 0x003c, "MotionWakeup" }, + { 0x01, 0x003d, "Start" }, + { 0x01, 0x003e, "Select" }, + { 0x01, 0x0040, "Vx" }, + { 0x01, 0x0041, "Vy" }, + { 0x01, 0x0042, "Vz" }, + { 0x01, 0x0043, "Vbrx" }, + { 0x01, 0x0044, "Vbry" }, + { 0x01, 0x0045, "Vbrz" }, + { 0x01, 0x0046, "Vno" }, + { 0x01, 0x0047, "FeatureNotification" }, + { 0x01, 0x0048, "ResolutionMultiplier" }, + { 0x01, 0x0049, "Qx" }, + { 0x01, 0x004a, "Qy" }, + { 0x01, 0x004b, "Qz" }, + { 0x01, 0x004c, "Qw" }, + { 0x01, 0x0080, "SystemControl" }, + { 0x01, 0x0081, "SystemPowerDown" }, + { 0x01, 0x0082, "SystemSleep" }, + { 0x01, 0x0083, "SystemWakeUp" }, + { 0x01, 0x0084, "SystemContextMenu" }, + { 0x01, 0x0085, "SystemMainMenu" }, + { 0x01, 0x0086, "SystemAppMenu" }, + { 0x01, 0x0087, "SystemMenuHelp" }, + { 0x01, 0x0088, "SystemMenuExit" }, + { 0x01, 0x0089, "SystemMenuSelect" }, + { 0x01, 0x008a, "SystemMenuRight" }, + { 0x01, 0x008b, "SystemMenuLeft" }, + { 0x01, 0x008c, "SystemMenuUp" }, + { 0x01, 0x008d, "SystemMenuDown" }, + { 0x01, 0x008e, "SystemColdRestart" }, + { 0x01, 0x008f, "SystemWarmRestart" }, + { 0x01, 0x0090, "DpadUp" }, + { 0x01, 0x0091, "DpadDown" }, + { 0x01, 0x0092, "DpadRight" }, + { 0x01, 0x0093, "DpadLeft" }, + { 0x01, 0x0094, "IndexTrigger" }, + { 0x01, 0x0095, "PalmTrigger" }, + { 0x01, 0x0096, "Thumbstick" }, + { 0x01, 0x0097, "SystemFunctionShift" }, + { 0x01, 0x0098, "SystemFunctionShiftLock" }, + { 0x01, 0x0099, "SystemFunctionShiftLockIndicator" }, + { 0x01, 0x009a, "SystemDismissNotification" }, + { 0x01, 0x009b, "SystemDoNotDisturb" }, + { 0x01, 0x00a0, "SystemDock" }, + { 0x01, 0x00a1, "SystemUndock" }, + { 0x01, 0x00a2, "SystemSetup" }, + { 0x01, 0x00a3, "SystemBreak" }, + { 0x01, 0x00a4, "SystemDebuggerBreak" }, + { 0x01, 0x00a5, "ApplicationBreak" }, + { 0x01, 0x00a6, "ApplicationDebuggerBreak" }, + { 0x01, 0x00a7, "SystemSpeakerMute" }, + { 0x01, 0x00a8, "SystemHibernate" }, + { 0x01, 0x00a9, "SystemMicrophoneMute" }, + { 0x01, 0x00b0, "SystemDisplayInvert" }, + { 0x01, 0x00b1, "SystemDisplayInternal" }, + { 0x01, 0x00b2, "SystemDisplayExternal" }, + { 0x01, 0x00b3, "SystemDisplayBoth" }, + { 0x01, 0x00b4, "SystemDisplayDual" }, + { 0x01, 0x00b5, "SystemDisplayToggleIntExtMode" }, + { 0x01, 0x00b6, "SystemDisplaySwapPrimarySecondary" }, + { 0x01, 0x00b7, "SystemDisplayToggleLCDAutoscale" }, + { 0x01, 0x00c0, "SensorZone" }, + { 0x01, 0x00c1, "RPM" }, + { 0x01, 0x00c2, "CoolantLevel" }, + { 0x01, 0x00c3, "CoolantCriticalLevel" }, + { 0x01, 0x00c4, "CoolantPump" }, + { 0x01, 0x00c5, "ChassisEnclosure" }, + { 0x01, 0x00c6, "WirelessRadioButton" }, + { 0x01, 0x00c7, "WirelessRadioLED" }, + { 0x01, 0x00c8, "WirelessRadioSliderSwitch" }, + { 0x01, 0x00c9, "SystemDisplayRotationLockButton" }, + { 0x01, 0x00ca, "SystemDisplayRotationLockSliderSwitch" }, + { 0x01, 0x00cb, "ControlEnable" }, + { 0x01, 0x00d0, "DockableDeviceUniqueID" }, + { 0x01, 0x00d1, "DockableDeviceVendorID" }, + { 0x01, 0x00d2, "DockableDevicePrimaryUsagePage" }, + { 0x01, 0x00d3, "DockableDevicePrimaryUsageID" }, + { 0x01, 0x00d4, "DockableDeviceDockingState" }, + { 0x01, 0x00d5, "DockableDeviceDisplayOcclusion" }, + { 0x01, 0x00d6, "DockableDeviceObjectType" }, + { 0x01, 0x00e0, "CallActiveLED" }, + { 0x01, 0x00e1, "CallMuteToggle" }, + { 0x01, 0x00e2, "CallMuteLED" }, + { 0x02, 0, "SimulationControls" }, + { 0x02, 0x0001, "FlightSimulationDevice" }, + { 0x02, 0x0002, "AutomobileSimulationDevice" }, + { 0x02, 0x0003, "TankSimulationDevice" }, + { 0x02, 0x0004, "SpaceshipSimulationDevice" }, + { 0x02, 0x0005, "SubmarineSimulationDevice" }, + { 0x02, 0x0006, "SailingSimulationDevice" }, + { 0x02, 0x0007, "MotorcycleSimulationDevice" }, + { 0x02, 0x0008, "SportsSimulationDevice" }, + { 0x02, 0x0009, "AirplaneSimulationDevice" }, + { 0x02, 0x000a, "HelicopterSimulationDevice" }, + { 0x02, 0x000b, "MagicCarpetSimulationDevice" }, + { 0x02, 0x000c, "BicycleSimulationDevice" }, + { 0x02, 0x0020, "FlightControlStick" }, + { 0x02, 0x0021, "FlightStick" }, + { 0x02, 0x0022, "CyclicControl" }, + { 0x02, 0x0023, "CyclicTrim" }, + { 0x02, 0x0024, "FlightYoke" }, + { 0x02, 0x0025, "TrackControl" }, + { 0x02, 0x00b0, "Aileron" }, + { 0x02, 0x00b1, "AileronTrim" }, + { 0x02, 0x00b2, "AntiTorqueControl" }, + { 0x02, 0x00b3, "AutopilotEnable" }, + { 0x02, 0x00b4, "ChaffRelease" }, + { 0x02, 0x00b5, "CollectiveControl" }, + { 0x02, 0x00b6, "DiveBrake" }, + { 0x02, 0x00b7, "ElectronicCountermeasures" }, + { 0x02, 0x00b8, "Elevator" }, + { 0x02, 0x00b9, "ElevatorTrim" }, + { 0x02, 0x00ba, "Rudder" }, + { 0x02, 0x00bb, "Throttle" }, + { 0x02, 0x00bc, "FlightCommunications" }, + { 0x02, 0x00bd, "FlareRelease" }, + { 0x02, 0x00be, "LandingGear" }, + { 0x02, 0x00bf, "ToeBrake" }, + { 0x02, 0x00c0, "Trigger" }, + { 0x02, 0x00c1, "WeaponsArm" }, + { 0x02, 0x00c2, "WeaponsSelect" }, + { 0x02, 0x00c3, "WingFlaps" }, + { 0x02, 0x00c4, "Accelerator" }, + { 0x02, 0x00c5, "Brake" }, + { 0x02, 0x00c6, "Clutch" }, + { 0x02, 0x00c7, "Shifter" }, + { 0x02, 0x00c8, "Steering" }, + { 0x02, 0x00c9, "TurretDirection" }, + { 0x02, 0x00ca, "BarrelElevation" }, + { 0x02, 0x00cb, "DivePlane" }, + { 0x02, 0x00cc, "Ballast" }, + { 0x02, 0x00cd, "BicycleCrank" }, + { 0x02, 0x00ce, "HandleBars" }, + { 0x02, 0x00cf, "FrontBrake" }, + { 0x02, 0x00d0, "RearBrake" }, + { 0x03, 0, "VRControls" }, + { 0x03, 0x0001, "Belt" }, + { 0x03, 0x0002, "BodySuit" }, + { 0x03, 0x0003, "Flexor" }, + { 0x03, 0x0004, "Glove" }, + { 0x03, 0x0005, "HeadTracker" }, + { 0x03, 0x0006, "HeadMountedDisplay" }, + { 0x03, 0x0007, "HandTracker" }, + { 0x03, 0x0008, "Oculometer" }, + { 0x03, 0x0009, "Vest" }, + { 0x03, 0x000a, "AnimatronicDevice" }, + { 0x03, 0x0020, "StereoEnable" }, + { 0x03, 0x0021, "DisplayEnable" }, + { 0x04, 0, "SportControls" }, + { 0x04, 0x0001, "BaseballBat" }, + { 0x04, 0x0002, "GolfClub" }, + { 0x04, 0x0003, "RowingMachine" }, + { 0x04, 0x0004, "Treadmill" }, + { 0x04, 0x0030, "Oar" }, + { 0x04, 0x0031, "Slope" }, + { 0x04, 0x0032, "Rate" }, + { 0x04, 0x0033, "StickSpeed" }, + { 0x04, 0x0034, "StickFaceAngle" }, + { 0x04, 0x0035, "StickHeelToe" }, + { 0x04, 0x0036, "StickFollowThrough" }, + { 0x04, 0x0037, "StickTempo" }, + { 0x04, 0x0038, "StickType" }, + { 0x04, 0x0039, "StickHeight" }, + { 0x04, 0x0050, "Putter" }, + { 0x04, 0x0051, "1Iron" }, + { 0x04, 0x0052, "2Iron" }, + { 0x04, 0x0053, "3Iron" }, + { 0x04, 0x0054, "4Iron" }, + { 0x04, 0x0055, "5Iron" }, + { 0x04, 0x0056, "6Iron" }, + { 0x04, 0x0057, "7Iron" }, + { 0x04, 0x0058, "8Iron" }, + { 0x04, 0x0059, "9Iron" }, + { 0x04, 0x005a, "10Iron" }, + { 0x04, 0x005b, "11Iron" }, + { 0x04, 0x005c, "SandWedge" }, + { 0x04, 0x005d, "LoftWedge" }, + { 0x04, 0x005e, "PowerWedge" }, + { 0x04, 0x005f, "1Wood" }, + { 0x04, 0x0060, "3Wood" }, + { 0x04, 0x0061, "5Wood" }, + { 0x04, 0x0062, "7Wood" }, + { 0x04, 0x0063, "9Wood" }, + { 0x05, 0, "GameControls" }, + { 0x05, 0x0001, "3DGameController" }, + { 0x05, 0x0002, "PinballDevice" }, + { 0x05, 0x0003, "GunDevice" }, + { 0x05, 0x0020, "PointofView" }, + { 0x05, 0x0021, "TurnRightLeft" }, + { 0x05, 0x0022, "PitchForwardBackward" }, + { 0x05, 0x0023, "RollRightLeft" }, + { 0x05, 0x0024, "MoveRightLeft" }, + { 0x05, 0x0025, "MoveForwardBackward" }, + { 0x05, 0x0026, "MoveUpDown" }, + { 0x05, 0x0027, "LeanRightLeft" }, + { 0x05, 0x0028, "LeanForwardBackward" }, + { 0x05, 0x0029, "HeightofPOV" }, + { 0x05, 0x002a, "Flipper" }, + { 0x05, 0x002b, "SecondaryFlipper" }, + { 0x05, 0x002c, "Bump" }, + { 0x05, 0x002d, "NewGame" }, + { 0x05, 0x002e, "ShootBall" }, + { 0x05, 0x002f, "Player" }, + { 0x05, 0x0030, "GunBolt" }, + { 0x05, 0x0031, "GunClip" }, + { 0x05, 0x0032, "GunSelector" }, + { 0x05, 0x0033, "GunSingleShot" }, + { 0x05, 0x0034, "GunBurst" }, + { 0x05, 0x0035, "GunAutomatic" }, + { 0x05, 0x0036, "GunSafety" }, + { 0x05, 0x0037, "GamepadFireJump" }, + { 0x05, 0x0039, "GamepadTrigger" }, + { 0x05, 0x003a, "FormfittingGamepad" }, + { 0x06, 0, "GenericDeviceControls" }, + { 0x06, 0x0001, "BackgroundNonuserControls" }, + { 0x06, 0x0020, "BatteryStrength" }, + { 0x06, 0x0021, "WirelessChannel" }, + { 0x06, 0x0022, "WirelessID" }, + { 0x06, 0x0023, "DiscoverWirelessControl" }, + { 0x06, 0x0024, "SecurityCodeCharacterEntered" }, + { 0x06, 0x0025, "SecurityCodeCharacterErased" }, + { 0x06, 0x0026, "SecurityCodeCleared" }, + { 0x06, 0x0027, "SequenceID" }, + { 0x06, 0x0028, "SequenceIDReset" }, + { 0x06, 0x0029, "RFSignalStrength" }, + { 0x06, 0x002a, "SoftwareVersion" }, + { 0x06, 0x002b, "ProtocolVersion" }, + { 0x06, 0x002c, "HardwareVersion" }, + { 0x06, 0x002d, "Major" }, + { 0x06, 0x002e, "Minor" }, + { 0x06, 0x002f, "Revision" }, + { 0x06, 0x0030, "Handedness" }, + { 0x06, 0x0031, "EitherHand" }, + { 0x06, 0x0032, "LeftHand" }, + { 0x06, 0x0033, "RightHand" }, + { 0x06, 0x0034, "BothHands" }, + { 0x06, 0x0040, "GripPoseOffset" }, + { 0x06, 0x0041, "PointerPoseOffset" }, + { 0x07, 0, "KeyboardKeypad" }, + { 0x07, 0x0001, "ErrorRollOver" }, + { 0x07, 0x0002, "POSTFail" }, + { 0x07, 0x0003, "ErrorUndefined" }, + { 0x07, 0x0004, "KeyboardA" }, + { 0x07, 0x0005, "KeyboardB" }, + { 0x07, 0x0006, "KeyboardC" }, + { 0x07, 0x0007, "KeyboardD" }, + { 0x07, 0x0008, "KeyboardE" }, + { 0x07, 0x0009, "KeyboardF" }, + { 0x07, 0x000a, "KeyboardG" }, + { 0x07, 0x000b, "KeyboardH" }, + { 0x07, 0x000c, "KeyboardI" }, + { 0x07, 0x000d, "KeyboardJ" }, + { 0x07, 0x000e, "KeyboardK" }, + { 0x07, 0x000f, "KeyboardL" }, + { 0x07, 0x0010, "KeyboardM" }, + { 0x07, 0x0011, "KeyboardN" }, + { 0x07, 0x0012, "KeyboardO" }, + { 0x07, 0x0013, "KeyboardP" }, + { 0x07, 0x0014, "KeyboardQ" }, + { 0x07, 0x0015, "KeyboardR" }, + { 0x07, 0x0016, "KeyboardS" }, + { 0x07, 0x0017, "KeyboardT" }, + { 0x07, 0x0018, "KeyboardU" }, + { 0x07, 0x0019, "KeyboardV" }, + { 0x07, 0x001a, "KeyboardW" }, + { 0x07, 0x001b, "KeyboardX" }, + { 0x07, 0x001c, "KeyboardY" }, + { 0x07, 0x001d, "KeyboardZ" }, + { 0x07, 0x001e, "Keyboard1andBang" }, + { 0x07, 0x001f, "Keyboard2andAt" }, + { 0x07, 0x0020, "Keyboard3andHash" }, + { 0x07, 0x0021, "Keyboard4andDollar" }, + { 0x07, 0x0022, "Keyboard5andPercent" }, + { 0x07, 0x0023, "Keyboard6andCaret" }, + { 0x07, 0x0024, "Keyboard7andAmpersand" }, + { 0x07, 0x0025, "Keyboard8andStar" }, + { 0x07, 0x0026, "Keyboard9andLeftBracket" }, + { 0x07, 0x0027, "Keyboard0andRightBracket" }, + { 0x07, 0x0028, "KeyboardReturnEnter" }, + { 0x07, 0x0029, "KeyboardEscape" }, + { 0x07, 0x002a, "KeyboardDelete" }, + { 0x07, 0x002b, "KeyboardTab" }, + { 0x07, 0x002c, "KeyboardSpacebar" }, + { 0x07, 0x002d, "KeyboardDashandUnderscore" }, + { 0x07, 0x002e, "KeyboardEqualsandPlus" }, + { 0x07, 0x002f, "KeyboardLeftBrace" }, + { 0x07, 0x0030, "KeyboardRightBrace" }, + { 0x07, 0x0031, "KeyboardBackslashandPipe" }, + { 0x07, 0x0032, "KeyboardNonUSHashandTilde" }, + { 0x07, 0x0033, "KeyboardSemiColonandColon" }, + { 0x07, 0x0034, "KeyboardLeftAposandDouble" }, + { 0x07, 0x0035, "KeyboardGraveAccentandTilde" }, + { 0x07, 0x0036, "KeyboardCommaandLessThan" }, + { 0x07, 0x0037, "KeyboardPeriodandGreaterThan" }, + { 0x07, 0x0038, "KeyboardForwardSlashandQuestionMark" }, + { 0x07, 0x0039, "KeyboardCapsLock" }, + { 0x07, 0x003a, "KeyboardF1" }, + { 0x07, 0x003b, "KeyboardF2" }, + { 0x07, 0x003c, "KeyboardF3" }, + { 0x07, 0x003d, "KeyboardF4" }, + { 0x07, 0x003e, "KeyboardF5" }, + { 0x07, 0x003f, "KeyboardF6" }, + { 0x07, 0x0040, "KeyboardF7" }, + { 0x07, 0x0041, "KeyboardF8" }, + { 0x07, 0x0042, "KeyboardF9" }, + { 0x07, 0x0043, "KeyboardF10" }, + { 0x07, 0x0044, "KeyboardF11" }, + { 0x07, 0x0045, "KeyboardF12" }, + { 0x07, 0x0046, "KeyboardPrintScreen" }, + { 0x07, 0x0047, "KeyboardScrollLock" }, + { 0x07, 0x0048, "KeyboardPause" }, + { 0x07, 0x0049, "KeyboardInsert" }, + { 0x07, 0x004a, "KeyboardHome" }, + { 0x07, 0x004b, "KeyboardPageUp" }, + { 0x07, 0x004c, "KeyboardDeleteForward" }, + { 0x07, 0x004d, "KeyboardEnd" }, + { 0x07, 0x004e, "KeyboardPageDown" }, + { 0x07, 0x004f, "KeyboardRightArrow" }, + { 0x07, 0x0050, "KeyboardLeftArrow" }, + { 0x07, 0x0051, "KeyboardDownArrow" }, + { 0x07, 0x0052, "KeyboardUpArrow" }, + { 0x07, 0x0053, "KeypadNumLockandClear" }, + { 0x07, 0x0054, "KeypadForwardSlash" }, + { 0x07, 0x0055, "KeypadStar" }, + { 0x07, 0x0056, "KeypadDash" }, + { 0x07, 0x0057, "KeypadPlus" }, + { 0x07, 0x0058, "KeypadENTER" }, + { 0x07, 0x0059, "Keypad1andEnd" }, + { 0x07, 0x005a, "Keypad2andDownArrow" }, + { 0x07, 0x005b, "Keypad3andPageDn" }, + { 0x07, 0x005c, "Keypad4andLeftArrow" }, + { 0x07, 0x005d, "Keypad5" }, + { 0x07, 0x005e, "Keypad6andRightArrow" }, + { 0x07, 0x005f, "Keypad7andHome" }, + { 0x07, 0x0060, "Keypad8andUpArrow" }, + { 0x07, 0x0061, "Keypad9andPageUp" }, + { 0x07, 0x0062, "Keypad0andInsert" }, + { 0x07, 0x0063, "KeypadPeriodandDelete" }, + { 0x07, 0x0064, "KeyboardNonUSBackslashandPipe" }, + { 0x07, 0x0065, "KeyboardApplication" }, + { 0x07, 0x0066, "KeyboardPower" }, + { 0x07, 0x0067, "KeypadEquals" }, + { 0x07, 0x0068, "KeyboardF13" }, + { 0x07, 0x0069, "KeyboardF14" }, + { 0x07, 0x006a, "KeyboardF15" }, + { 0x07, 0x006b, "KeyboardF16" }, + { 0x07, 0x006c, "KeyboardF17" }, + { 0x07, 0x006d, "KeyboardF18" }, + { 0x07, 0x006e, "KeyboardF19" }, + { 0x07, 0x006f, "KeyboardF20" }, + { 0x07, 0x0070, "KeyboardF21" }, + { 0x07, 0x0071, "KeyboardF22" }, + { 0x07, 0x0072, "KeyboardF23" }, + { 0x07, 0x0073, "KeyboardF24" }, + { 0x07, 0x0074, "KeyboardExecute" }, + { 0x07, 0x0075, "KeyboardHelp" }, + { 0x07, 0x0076, "KeyboardMenu" }, + { 0x07, 0x0077, "KeyboardSelect" }, + { 0x07, 0x0078, "KeyboardStop" }, + { 0x07, 0x0079, "KeyboardAgain" }, + { 0x07, 0x007a, "KeyboardUndo" }, + { 0x07, 0x007b, "KeyboardCut" }, + { 0x07, 0x007c, "KeyboardCopy" }, + { 0x07, 0x007d, "KeyboardPaste" }, + { 0x07, 0x007e, "KeyboardFind" }, + { 0x07, 0x007f, "KeyboardMute" }, + { 0x07, 0x0080, "KeyboardVolumeUp" }, + { 0x07, 0x0081, "KeyboardVolumeDown" }, + { 0x07, 0x0082, "KeyboardLockingCapsLock" }, + { 0x07, 0x0083, "KeyboardLockingNumLock" }, + { 0x07, 0x0084, "KeyboardLockingScrollLock" }, + { 0x07, 0x0085, "KeypadComma" }, + { 0x07, 0x0086, "KeypadEqualSign" }, + { 0x07, 0x0087, "KeyboardInternational1" }, + { 0x07, 0x0088, "KeyboardInternational2" }, + { 0x07, 0x0089, "KeyboardInternational3" }, + { 0x07, 0x008a, "KeyboardInternational4" }, + { 0x07, 0x008b, "KeyboardInternational5" }, + { 0x07, 0x008c, "KeyboardInternational6" }, + { 0x07, 0x008d, "KeyboardInternational7" }, + { 0x07, 0x008e, "KeyboardInternational8" }, + { 0x07, 0x008f, "KeyboardInternational9" }, + { 0x07, 0x0090, "KeyboardLANG1" }, + { 0x07, 0x0091, "KeyboardLANG2" }, + { 0x07, 0x0092, "KeyboardLANG3" }, + { 0x07, 0x0093, "KeyboardLANG4" }, + { 0x07, 0x0094, "KeyboardLANG5" }, + { 0x07, 0x0095, "KeyboardLANG6" }, + { 0x07, 0x0096, "KeyboardLANG7" }, + { 0x07, 0x0097, "KeyboardLANG8" }, + { 0x07, 0x0098, "KeyboardLANG9" }, + { 0x07, 0x0099, "KeyboardAlternateErase" }, + { 0x07, 0x009a, "KeyboardSysReqAttention" }, + { 0x07, 0x009b, "KeyboardCancel" }, + { 0x07, 0x009c, "KeyboardClear" }, + { 0x07, 0x009d, "KeyboardPrior" }, + { 0x07, 0x009e, "KeyboardReturn" }, + { 0x07, 0x009f, "KeyboardSeparator" }, + { 0x07, 0x00a0, "KeyboardOut" }, + { 0x07, 0x00a1, "KeyboardOper" }, + { 0x07, 0x00a2, "KeyboardClearAgain" }, + { 0x07, 0x00a3, "KeyboardCrSelProps" }, + { 0x07, 0x00a4, "KeyboardExSel" }, + { 0x07, 0x00b0, "KeypadDouble0" }, + { 0x07, 0x00b1, "KeypadTriple0" }, + { 0x07, 0x00b2, "ThousandsSeparator" }, + { 0x07, 0x00b3, "DecimalSeparator" }, + { 0x07, 0x00b4, "CurrencyUnit" }, + { 0x07, 0x00b5, "CurrencySubunit" }, + { 0x07, 0x00b6, "KeypadLeftBracket" }, + { 0x07, 0x00b7, "KeypadRightBracket" }, + { 0x07, 0x00b8, "KeypadLeftBrace" }, + { 0x07, 0x00b9, "KeypadRightBrace" }, + { 0x07, 0x00ba, "KeypadTab" }, + { 0x07, 0x00bb, "KeypadBackspace" }, + { 0x07, 0x00bc, "KeypadA" }, + { 0x07, 0x00bd, "KeypadB" }, + { 0x07, 0x00be, "KeypadC" }, + { 0x07, 0x00bf, "KeypadD" }, + { 0x07, 0x00c0, "KeypadE" }, + { 0x07, 0x00c1, "KeypadF" }, + { 0x07, 0x00c2, "KeypadXOR" }, + { 0x07, 0x00c3, "KeypadCaret" }, + { 0x07, 0x00c4, "KeypadPercentage" }, + { 0x07, 0x00c5, "KeypadLess" }, + { 0x07, 0x00c6, "KeypadGreater" }, + { 0x07, 0x00c7, "KeypadAmpersand" }, + { 0x07, 0x00c8, "KeypadDoubleAmpersand" }, + { 0x07, 0x00c9, "KeypadBar" }, + { 0x07, 0x00ca, "KeypadDoubleBar" }, + { 0x07, 0x00cb, "KeypadColon" }, + { 0x07, 0x00cc, "KeypadHash" }, + { 0x07, 0x00cd, "KeypadSpace" }, + { 0x07, 0x00ce, "KeypadAt" }, + { 0x07, 0x00cf, "KeypadBang" }, + { 0x07, 0x00d0, "KeypadMemoryStore" }, + { 0x07, 0x00d1, "KeypadMemoryRecall" }, + { 0x07, 0x00d2, "KeypadMemoryClear" }, + { 0x07, 0x00d3, "KeypadMemoryAdd" }, + { 0x07, 0x00d4, "KeypadMemorySubtract" }, + { 0x07, 0x00d5, "KeypadMemoryMultiply" }, + { 0x07, 0x00d6, "KeypadMemoryDivide" }, + { 0x07, 0x00d7, "KeypadPlusMinus" }, + { 0x07, 0x00d8, "KeypadClear" }, + { 0x07, 0x00d9, "KeypadClearEntry" }, + { 0x07, 0x00da, "KeypadBinary" }, + { 0x07, 0x00db, "KeypadOctal" }, + { 0x07, 0x00dc, "KeypadDecimal" }, + { 0x07, 0x00dd, "KeypadHexadecimal" }, + { 0x07, 0x00e0, "KeyboardLeftControl" }, + { 0x07, 0x00e1, "KeyboardLeftShift" }, + { 0x07, 0x00e2, "KeyboardLeftAlt" }, + { 0x07, 0x00e3, "KeyboardLeftGUI" }, + { 0x07, 0x00e4, "KeyboardRightControl" }, + { 0x07, 0x00e5, "KeyboardRightShift" }, + { 0x07, 0x00e6, "KeyboardRightAlt" }, + { 0x07, 0x00e7, "KeyboardRightGUI" }, + { 0x08, 0, "LED" }, + { 0x08, 0x0001, "NumLock" }, + { 0x08, 0x0002, "CapsLock" }, + { 0x08, 0x0003, "ScrollLock" }, + { 0x08, 0x0004, "Compose" }, + { 0x08, 0x0005, "Kana" }, + { 0x08, 0x0006, "Power" }, + { 0x08, 0x0007, "Shift" }, + { 0x08, 0x0008, "DoNotDisturb" }, + { 0x08, 0x0009, "Mute" }, + { 0x08, 0x000a, "ToneEnable" }, + { 0x08, 0x000b, "HighCutFilter" }, + { 0x08, 0x000c, "LowCutFilter" }, + { 0x08, 0x000d, "EqualizerEnable" }, + { 0x08, 0x000e, "SoundFieldOn" }, + { 0x08, 0x000f, "SurroundOn" }, + { 0x08, 0x0010, "Repeat" }, + { 0x08, 0x0011, "Stereo" }, + { 0x08, 0x0012, "SamplingRateDetect" }, + { 0x08, 0x0013, "Spinning" }, + { 0x08, 0x0014, "CAV" }, + { 0x08, 0x0015, "CLV" }, + { 0x08, 0x0016, "RecordingFormatDetect" }, + { 0x08, 0x0017, "OffHook" }, + { 0x08, 0x0018, "Ring" }, + { 0x08, 0x0019, "MessageWaiting" }, + { 0x08, 0x001a, "DataMode" }, + { 0x08, 0x001b, "BatteryOperation" }, + { 0x08, 0x001c, "BatteryOK" }, + { 0x08, 0x001d, "BatteryLow" }, + { 0x08, 0x001e, "Speaker" }, + { 0x08, 0x001f, "Headset" }, + { 0x08, 0x0020, "Hold" }, + { 0x08, 0x0021, "Microphone" }, + { 0x08, 0x0022, "Coverage" }, + { 0x08, 0x0023, "NightMode" }, + { 0x08, 0x0024, "SendCalls" }, + { 0x08, 0x0025, "CallPickup" }, + { 0x08, 0x0026, "Conference" }, + { 0x08, 0x0027, "Standby" }, + { 0x08, 0x0028, "CameraOn" }, + { 0x08, 0x0029, "CameraOff" }, + { 0x08, 0x002a, "OnLine" }, + { 0x08, 0x002b, "OffLine" }, + { 0x08, 0x002c, "Busy" }, + { 0x08, 0x002d, "Ready" }, + { 0x08, 0x002e, "PaperOut" }, + { 0x08, 0x002f, "PaperJam" }, + { 0x08, 0x0030, "Remote" }, + { 0x08, 0x0031, "Forward" }, + { 0x08, 0x0032, "Reverse" }, + { 0x08, 0x0033, "Stop" }, + { 0x08, 0x0034, "Rewind" }, + { 0x08, 0x0035, "FastForward" }, + { 0x08, 0x0036, "Play" }, + { 0x08, 0x0037, "Pause" }, + { 0x08, 0x0038, "Record" }, + { 0x08, 0x0039, "Error" }, + { 0x08, 0x003a, "UsageSelectedIndicator" }, + { 0x08, 0x003b, "UsageInUseIndicator" }, + { 0x08, 0x003c, "UsageMultiModeIndicator" }, + { 0x08, 0x003d, "IndicatorOn" }, + { 0x08, 0x003e, "IndicatorFlash" }, + { 0x08, 0x003f, "IndicatorSlowBlink" }, + { 0x08, 0x0040, "IndicatorFastBlink" }, + { 0x08, 0x0041, "IndicatorOff" }, + { 0x08, 0x0042, "FlashOnTime" }, + { 0x08, 0x0043, "SlowBlinkOnTime" }, + { 0x08, 0x0044, "SlowBlinkOffTime" }, + { 0x08, 0x0045, "FastBlinkOnTime" }, + { 0x08, 0x0046, "FastBlinkOffTime" }, + { 0x08, 0x0047, "UsageIndicatorColor" }, + { 0x08, 0x0048, "IndicatorRed" }, + { 0x08, 0x0049, "IndicatorGreen" }, + { 0x08, 0x004a, "IndicatorAmber" }, + { 0x08, 0x004b, "GenericIndicator" }, + { 0x08, 0x004c, "SystemSuspend" }, + { 0x08, 0x004d, "ExternalPowerConnected" }, + { 0x08, 0x004e, "IndicatorBlue" }, + { 0x08, 0x004f, "IndicatorOrange" }, + { 0x08, 0x0050, "GoodStatus" }, + { 0x08, 0x0051, "WarningStatus" }, + { 0x08, 0x0052, "RGBLED" }, + { 0x08, 0x0053, "RedLEDChannel" }, + { 0x08, 0x0054, "BlueLEDChannel" }, + { 0x08, 0x0055, "GreenLEDChannel" }, + { 0x08, 0x0056, "LEDIntensity" }, + { 0x08, 0x0057, "SystemMicrophoneMute" }, + { 0x08, 0x0060, "PlayerIndicator" }, + { 0x08, 0x0061, "Player1" }, + { 0x08, 0x0062, "Player2" }, + { 0x08, 0x0063, "Player3" }, + { 0x08, 0x0064, "Player4" }, + { 0x08, 0x0065, "Player5" }, + { 0x08, 0x0066, "Player6" }, + { 0x08, 0x0067, "Player7" }, + { 0x08, 0x0068, "Player8" }, + { 0x09, 0, "Button" }, + { 0x0a, 0, "Ordinal" }, + { 0x0b, 0, "TelephonyDevice" }, + { 0x0b, 0x0001, "Phone" }, + { 0x0b, 0x0002, "AnsweringMachine" }, + { 0x0b, 0x0003, "MessageControls" }, + { 0x0b, 0x0004, "Handset" }, + { 0x0b, 0x0005, "Headset" }, + { 0x0b, 0x0006, "TelephonyKeyPad" }, + { 0x0b, 0x0007, "ProgrammableButton" }, + { 0x0b, 0x0020, "HookSwitch" }, + { 0x0b, 0x0021, "Flash" }, + { 0x0b, 0x0022, "Feature" }, + { 0x0b, 0x0023, "Hold" }, + { 0x0b, 0x0024, "Redial" }, + { 0x0b, 0x0025, "Transfer" }, + { 0x0b, 0x0026, "Drop" }, + { 0x0b, 0x0027, "Park" }, + { 0x0b, 0x0028, "ForwardCalls" }, + { 0x0b, 0x0029, "AlternateFunction" }, + { 0x0b, 0x002a, "Line" }, + { 0x0b, 0x002b, "SpeakerPhone" }, + { 0x0b, 0x002c, "Conference" }, + { 0x0b, 0x002d, "RingEnable" }, + { 0x0b, 0x002e, "RingSelect" }, + { 0x0b, 0x002f, "PhoneMute" }, + { 0x0b, 0x0030, "CallerID" }, + { 0x0b, 0x0031, "Send" }, + { 0x0b, 0x0050, "SpeedDial" }, + { 0x0b, 0x0051, "StoreNumber" }, + { 0x0b, 0x0052, "RecallNumber" }, + { 0x0b, 0x0053, "PhoneDirectory" }, + { 0x0b, 0x0070, "VoiceMail" }, + { 0x0b, 0x0071, "ScreenCalls" }, + { 0x0b, 0x0072, "DoNotDisturb" }, + { 0x0b, 0x0073, "Message" }, + { 0x0b, 0x0074, "AnswerOnOff" }, + { 0x0b, 0x0090, "InsideDialTone" }, + { 0x0b, 0x0091, "OutsideDialTone" }, + { 0x0b, 0x0092, "InsideRingTone" }, + { 0x0b, 0x0093, "OutsideRingTone" }, + { 0x0b, 0x0094, "PriorityRingTone" }, + { 0x0b, 0x0095, "InsideRingback" }, + { 0x0b, 0x0096, "PriorityRingback" }, + { 0x0b, 0x0097, "LineBusyTone" }, + { 0x0b, 0x0098, "ReorderTone" }, + { 0x0b, 0x0099, "CallWaitingTone" }, + { 0x0b, 0x009a, "ConfirmationTone1" }, + { 0x0b, 0x009b, "ConfirmationTone2" }, + { 0x0b, 0x009c, "TonesOff" }, + { 0x0b, 0x009d, "OutsideRingback" }, + { 0x0b, 0x009e, "Ringer" }, + { 0x0b, 0x00b0, "PhoneKey0" }, + { 0x0b, 0x00b1, "PhoneKey1" }, + { 0x0b, 0x00b2, "PhoneKey2" }, + { 0x0b, 0x00b3, "PhoneKey3" }, + { 0x0b, 0x00b4, "PhoneKey4" }, + { 0x0b, 0x00b5, "PhoneKey5" }, + { 0x0b, 0x00b6, "PhoneKey6" }, + { 0x0b, 0x00b7, "PhoneKey7" }, + { 0x0b, 0x00b8, "PhoneKey8" }, + { 0x0b, 0x00b9, "PhoneKey9" }, + { 0x0b, 0x00ba, "PhoneKeyStar" }, + { 0x0b, 0x00bb, "PhoneKeyPound" }, + { 0x0b, 0x00bc, "PhoneKeyA" }, + { 0x0b, 0x00bd, "PhoneKeyB" }, + { 0x0b, 0x00be, "PhoneKeyC" }, + { 0x0b, 0x00bf, "PhoneKeyD" }, + { 0x0b, 0x00c0, "PhoneCallHistoryKey" }, + { 0x0b, 0x00c1, "PhoneCallerIDKey" }, + { 0x0b, 0x00c2, "PhoneSettingsKey" }, + { 0x0b, 0x00f0, "HostControl" }, + { 0x0b, 0x00f1, "HostAvailable" }, + { 0x0b, 0x00f2, "HostCallActive" }, + { 0x0b, 0x00f3, "ActivateHandsetAudio" }, + { 0x0b, 0x00f4, "RingType" }, + { 0x0b, 0x00f5, "RedialablePhoneNumber" }, + { 0x0b, 0x00f8, "StopRingTone" }, + { 0x0b, 0x00f9, "PSTNRingTone" }, + { 0x0b, 0x00fa, "HostRingTone" }, + { 0x0b, 0x00fb, "AlertSoundError" }, + { 0x0b, 0x00fc, "AlertSoundConfirm" }, + { 0x0b, 0x00fd, "AlertSoundNotification" }, + { 0x0b, 0x00fe, "SilentRing" }, + { 0x0b, 0x0108, "EmailMessageWaiting" }, + { 0x0b, 0x0109, "VoicemailMessageWaiting" }, + { 0x0b, 0x010a, "HostHold" }, + { 0x0b, 0x0110, "IncomingCallHistoryCount" }, + { 0x0b, 0x0111, "OutgoingCallHistoryCount" }, + { 0x0b, 0x0112, "IncomingCallHistory" }, + { 0x0b, 0x0113, "OutgoingCallHistory" }, + { 0x0b, 0x0114, "PhoneLocale" }, + { 0x0b, 0x0140, "PhoneTimeSecond" }, + { 0x0b, 0x0141, "PhoneTimeMinute" }, + { 0x0b, 0x0142, "PhoneTimeHour" }, + { 0x0b, 0x0143, "PhoneDateDay" }, + { 0x0b, 0x0144, "PhoneDateMonth" }, + { 0x0b, 0x0145, "PhoneDateYear" }, + { 0x0b, 0x0146, "HandsetNickname" }, + { 0x0b, 0x0147, "AddressBookID" }, + { 0x0b, 0x014a, "CallDuration" }, + { 0x0b, 0x014b, "DualModePhone" }, + { 0x0c, 0, "Consumer" }, + { 0x0c, 0x0001, "ConsumerControl" }, + { 0x0c, 0x0002, "NumericKeyPad" }, + { 0x0c, 0x0003, "ProgrammableButtons" }, + { 0x0c, 0x0004, "Microphone" }, + { 0x0c, 0x0005, "Headphone" }, + { 0x0c, 0x0006, "GraphicEqualizer" }, + { 0x0c, 0x0020, "10" }, + { 0x0c, 0x0021, "100" }, + { 0x0c, 0x0022, "AMPM" }, + { 0x0c, 0x0030, "Power" }, + { 0x0c, 0x0031, "Reset" }, + { 0x0c, 0x0032, "Sleep" }, + { 0x0c, 0x0033, "SleepAfter" }, + { 0x0c, 0x0034, "SleepMode" }, + { 0x0c, 0x0035, "Illumination" }, + { 0x0c, 0x0036, "FunctionButtons" }, + { 0x0c, 0x0040, "Menu" }, + { 0x0c, 0x0041, "MenuPick" }, + { 0x0c, 0x0042, "MenuUp" }, + { 0x0c, 0x0043, "MenuDown" }, + { 0x0c, 0x0044, "MenuLeft" }, + { 0x0c, 0x0045, "MenuRight" }, + { 0x0c, 0x0046, "MenuEscape" }, + { 0x0c, 0x0047, "MenuValueIncrease" }, + { 0x0c, 0x0048, "MenuValueDecrease" }, + { 0x0c, 0x0060, "DataOnScreen" }, + { 0x0c, 0x0061, "ClosedCaption" }, + { 0x0c, 0x0062, "ClosedCaptionSelect" }, + { 0x0c, 0x0063, "VCRTV" }, + { 0x0c, 0x0064, "BroadcastMode" }, + { 0x0c, 0x0065, "Snapshot" }, + { 0x0c, 0x0066, "Still" }, + { 0x0c, 0x0067, "PictureinPictureToggle" }, + { 0x0c, 0x0068, "PictureinPictureSwap" }, + { 0x0c, 0x0069, "RedMenuButton" }, + { 0x0c, 0x006a, "GreenMenuButton" }, + { 0x0c, 0x006b, "BlueMenuButton" }, + { 0x0c, 0x006c, "YellowMenuButton" }, + { 0x0c, 0x006d, "Aspect" }, + { 0x0c, 0x006e, "3DModeSelect" }, + { 0x0c, 0x006f, "DisplayBrightnessIncrement" }, + { 0x0c, 0x0070, "DisplayBrightnessDecrement" }, + { 0x0c, 0x0071, "DisplayBrightness" }, + { 0x0c, 0x0072, "DisplayBacklightToggle" }, + { 0x0c, 0x0073, "DisplaySetBrightnesstoMinimum" }, + { 0x0c, 0x0074, "DisplaySetBrightnesstoMaximum" }, + { 0x0c, 0x0075, "DisplaySetAutoBrightness" }, + { 0x0c, 0x0076, "CameraAccessEnabled" }, + { 0x0c, 0x0077, "CameraAccessDisabled" }, + { 0x0c, 0x0078, "CameraAccessToggle" }, + { 0x0c, 0x0079, "KeyboardBrightnessIncrement" }, + { 0x0c, 0x007a, "KeyboardBrightnessDecrement" }, + { 0x0c, 0x007b, "KeyboardBacklightSetLevel" }, + { 0x0c, 0x007c, "KeyboardBacklightOOC" }, + { 0x0c, 0x007d, "KeyboardBacklightSetMinimum" }, + { 0x0c, 0x007e, "KeyboardBacklightSetMaximum" }, + { 0x0c, 0x007f, "KeyboardBacklightAuto" }, + { 0x0c, 0x0080, "Selection" }, + { 0x0c, 0x0081, "AssignSelection" }, + { 0x0c, 0x0082, "ModeStep" }, + { 0x0c, 0x0083, "RecallLast" }, + { 0x0c, 0x0084, "EnterChannel" }, + { 0x0c, 0x0085, "OrderMovie" }, + { 0x0c, 0x0086, "Channel" }, + { 0x0c, 0x0087, "MediaSelection" }, + { 0x0c, 0x0088, "MediaSelectComputer" }, + { 0x0c, 0x0089, "MediaSelectTV" }, + { 0x0c, 0x008a, "MediaSelectWWW" }, + { 0x0c, 0x008b, "MediaSelectDVD" }, + { 0x0c, 0x008c, "MediaSelectTelephone" }, + { 0x0c, 0x008d, "MediaSelectProgramGuide" }, + { 0x0c, 0x008e, "MediaSelectVideoPhone" }, + { 0x0c, 0x008f, "MediaSelectGames" }, + { 0x0c, 0x0090, "MediaSelectMessages" }, + { 0x0c, 0x0091, "MediaSelectCD" }, + { 0x0c, 0x0092, "MediaSelectVCR" }, + { 0x0c, 0x0093, "MediaSelectTuner" }, + { 0x0c, 0x0094, "Quit" }, + { 0x0c, 0x0095, "Help" }, + { 0x0c, 0x0096, "MediaSelectTape" }, + { 0x0c, 0x0097, "MediaSelectCable" }, + { 0x0c, 0x0098, "MediaSelectSatellite" }, + { 0x0c, 0x0099, "MediaSelectSecurity" }, + { 0x0c, 0x009a, "MediaSelectHome" }, + { 0x0c, 0x009b, "MediaSelectCall" }, + { 0x0c, 0x009c, "ChannelIncrement" }, + { 0x0c, 0x009d, "ChannelDecrement" }, + { 0x0c, 0x009e, "MediaSelectSAP" }, + { 0x0c, 0x00a0, "VCRPlus" }, + { 0x0c, 0x00a1, "Once" }, + { 0x0c, 0x00a2, "Daily" }, + { 0x0c, 0x00a3, "Weekly" }, + { 0x0c, 0x00a4, "Monthly" }, + { 0x0c, 0x00b0, "Play" }, + { 0x0c, 0x00b1, "Pause" }, + { 0x0c, 0x00b2, "Record" }, + { 0x0c, 0x00b3, "FastForward" }, + { 0x0c, 0x00b4, "Rewind" }, + { 0x0c, 0x00b5, "ScanNextTrack" }, + { 0x0c, 0x00b6, "ScanPreviousTrack" }, + { 0x0c, 0x00b7, "Stop" }, + { 0x0c, 0x00b8, "Eject" }, + { 0x0c, 0x00b9, "RandomPlay" }, + { 0x0c, 0x00ba, "SelectDisc" }, + { 0x0c, 0x00bb, "EnterDisc" }, + { 0x0c, 0x00bc, "Repeat" }, + { 0x0c, 0x00bd, "Tracking" }, + { 0x0c, 0x00be, "TrackNormal" }, + { 0x0c, 0x00bf, "SlowTracking" }, + { 0x0c, 0x00c0, "FrameForward" }, + { 0x0c, 0x00c1, "FrameBack" }, + { 0x0c, 0x00c2, "Mark" }, + { 0x0c, 0x00c3, "ClearMark" }, + { 0x0c, 0x00c4, "RepeatFromMark" }, + { 0x0c, 0x00c5, "ReturnToMark" }, + { 0x0c, 0x00c6, "SearchMarkForward" }, + { 0x0c, 0x00c7, "SearchMarkBackwards" }, + { 0x0c, 0x00c8, "CounterReset" }, + { 0x0c, 0x00c9, "ShowCounter" }, + { 0x0c, 0x00ca, "TrackingIncrement" }, + { 0x0c, 0x00cb, "TrackingDecrement" }, + { 0x0c, 0x00cc, "StopEject" }, + { 0x0c, 0x00cd, "PlayPause" }, + { 0x0c, 0x00ce, "PlaySkip" }, + { 0x0c, 0x00cf, "VoiceCommand" }, + { 0x0c, 0x00d0, "InvokeCaptureInterface" }, + { 0x0c, 0x00d1, "StartorStopGameRecording" }, + { 0x0c, 0x00d2, "HistoricalGameCapture" }, + { 0x0c, 0x00d3, "CaptureGameScreenshot" }, + { 0x0c, 0x00d4, "ShoworHideRecordingIndicator" }, + { 0x0c, 0x00d5, "StartorStopMicrophoneCapture" }, + { 0x0c, 0x00d6, "StartorStopCameraCapture" }, + { 0x0c, 0x00d7, "StartorStopGameBroadcast" }, + { 0x0c, 0x00d8, "StartorStopVoiceDictationSession" }, + { 0x0c, 0x00d9, "InvokeDismissEmojiPicker" }, + { 0x0c, 0x00e0, "Volume" }, + { 0x0c, 0x00e1, "Balance" }, + { 0x0c, 0x00e2, "Mute" }, + { 0x0c, 0x00e3, "Bass" }, + { 0x0c, 0x00e4, "Treble" }, + { 0x0c, 0x00e5, "BassBoost" }, + { 0x0c, 0x00e6, "SurroundMode" }, + { 0x0c, 0x00e7, "Loudness" }, + { 0x0c, 0x00e8, "MPX" }, + { 0x0c, 0x00e9, "VolumeIncrement" }, + { 0x0c, 0x00ea, "VolumeDecrement" }, + { 0x0c, 0x00f0, "SpeedSelect" }, + { 0x0c, 0x00f1, "PlaybackSpeed" }, + { 0x0c, 0x00f2, "StandardPlay" }, + { 0x0c, 0x00f3, "LongPlay" }, + { 0x0c, 0x00f4, "ExtendedPlay" }, + { 0x0c, 0x00f5, "Slow" }, + { 0x0c, 0x0100, "FanEnable" }, + { 0x0c, 0x0101, "FanSpeed" }, + { 0x0c, 0x0102, "LightEnable" }, + { 0x0c, 0x0103, "LightIlluminationLevel" }, + { 0x0c, 0x0104, "ClimateControlEnable" }, + { 0x0c, 0x0105, "RoomTemperature" }, + { 0x0c, 0x0106, "SecurityEnable" }, + { 0x0c, 0x0107, "FireAlarm" }, + { 0x0c, 0x0108, "PoliceAlarm" }, + { 0x0c, 0x0109, "Proximity" }, + { 0x0c, 0x010a, "Motion" }, + { 0x0c, 0x010b, "DuressAlarm" }, + { 0x0c, 0x010c, "HoldupAlarm" }, + { 0x0c, 0x010d, "MedicalAlarm" }, + { 0x0c, 0x0150, "BalanceRight" }, + { 0x0c, 0x0151, "BalanceLeft" }, + { 0x0c, 0x0152, "BassIncrement" }, + { 0x0c, 0x0153, "BassDecrement" }, + { 0x0c, 0x0154, "TrebleIncrement" }, + { 0x0c, 0x0155, "TrebleDecrement" }, + { 0x0c, 0x0160, "SpeakerSystem" }, + { 0x0c, 0x0161, "ChannelLeft" }, + { 0x0c, 0x0162, "ChannelRight" }, + { 0x0c, 0x0163, "ChannelCenter" }, + { 0x0c, 0x0164, "ChannelFront" }, + { 0x0c, 0x0165, "ChannelCenterFront" }, + { 0x0c, 0x0166, "ChannelSide" }, + { 0x0c, 0x0167, "ChannelSurround" }, + { 0x0c, 0x0168, "ChannelLowFrequencyEnhancement" }, + { 0x0c, 0x0169, "ChannelTop" }, + { 0x0c, 0x016a, "ChannelUnknown" }, + { 0x0c, 0x0170, "Subchannel" }, + { 0x0c, 0x0171, "SubchannelIncrement" }, + { 0x0c, 0x0172, "SubchannelDecrement" }, + { 0x0c, 0x0173, "AlternateAudioIncrement" }, + { 0x0c, 0x0174, "AlternateAudioDecrement" }, + { 0x0c, 0x0180, "ApplicationLaunchButtons" }, + { 0x0c, 0x0181, "ALLaunchButtonConfigurationTool" }, + { 0x0c, 0x0182, "ALProgrammableButtonConfiguration" }, + { 0x0c, 0x0183, "ALConsumerControlConfiguration" }, + { 0x0c, 0x0184, "ALWordProcessor" }, + { 0x0c, 0x0185, "ALTextEditor" }, + { 0x0c, 0x0186, "ALSpreadsheet" }, + { 0x0c, 0x0187, "ALGraphicsEditor" }, + { 0x0c, 0x0188, "ALPresentationApp" }, + { 0x0c, 0x0189, "ALDatabaseApp" }, + { 0x0c, 0x018a, "ALEmailReader" }, + { 0x0c, 0x018b, "ALNewsreader" }, + { 0x0c, 0x018c, "ALVoicemail" }, + { 0x0c, 0x018d, "ALContactsAddressBook" }, + { 0x0c, 0x018e, "ALCalendarSchedule" }, + { 0x0c, 0x018f, "ALTaskProjectManager" }, + { 0x0c, 0x0190, "ALLogJournalTimecard" }, + { 0x0c, 0x0191, "ALCheckbookFinance" }, + { 0x0c, 0x0192, "ALCalculator" }, + { 0x0c, 0x0193, "ALAVCapturePlayback" }, + { 0x0c, 0x0194, "ALLocalMachineBrowser" }, + { 0x0c, 0x0195, "ALLANWANBrowser" }, + { 0x0c, 0x0196, "ALInternetBrowser" }, + { 0x0c, 0x0197, "ALRemoteNetworkingISPConnect" }, + { 0x0c, 0x0198, "ALNetworkConference" }, + { 0x0c, 0x0199, "ALNetworkChat" }, + { 0x0c, 0x019a, "ALTelephonyDialer" }, + { 0x0c, 0x019b, "ALLogon" }, + { 0x0c, 0x019c, "ALLogoff" }, + { 0x0c, 0x019d, "ALLogonLogoff" }, + { 0x0c, 0x019e, "ALTerminalLockScreensaver" }, + { 0x0c, 0x019f, "ALControlPanel" }, + { 0x0c, 0x01a0, "ALCommandLineProcessorRun" }, + { 0x0c, 0x01a1, "ALProcessTaskManager" }, + { 0x0c, 0x01a2, "ALSelectTaskApplication" }, + { 0x0c, 0x01a3, "ALNextTaskApplication" }, + { 0x0c, 0x01a4, "ALPreviousTaskApplication" }, + { 0x0c, 0x01a5, "ALPreemptiveHaltTaskApplication" }, + { 0x0c, 0x01a6, "ALIntegratedHelpCenter" }, + { 0x0c, 0x01a7, "ALDocuments" }, + { 0x0c, 0x01a8, "ALThesaurus" }, + { 0x0c, 0x01a9, "ALDictionary" }, + { 0x0c, 0x01aa, "ALDesktop" }, + { 0x0c, 0x01ab, "ALSpellCheck" }, + { 0x0c, 0x01ac, "ALGrammarCheck" }, + { 0x0c, 0x01ad, "ALWirelessStatus" }, + { 0x0c, 0x01ae, "ALKeyboardLayout" }, + { 0x0c, 0x01af, "ALVirusProtection" }, + { 0x0c, 0x01b0, "ALEncryption" }, + { 0x0c, 0x01b1, "ALScreenSaver" }, + { 0x0c, 0x01b2, "ALAlarms" }, + { 0x0c, 0x01b3, "ALClock" }, + { 0x0c, 0x01b4, "ALFileBrowser" }, + { 0x0c, 0x01b5, "ALPowerStatus" }, + { 0x0c, 0x01b6, "ALImageBrowser" }, + { 0x0c, 0x01b7, "ALAudioBrowser" }, + { 0x0c, 0x01b8, "ALMovieBrowser" }, + { 0x0c, 0x01b9, "ALDigitalRightsManager" }, + { 0x0c, 0x01ba, "ALDigitalWallet" }, + { 0x0c, 0x01bc, "ALInstantMessaging" }, + { 0x0c, 0x01bd, "ALOEMFeaturesTipsTutorialBrowser" }, + { 0x0c, 0x01be, "ALOEMHelp" }, + { 0x0c, 0x01bf, "ALOnlineCommunity" }, + { 0x0c, 0x01c0, "ALEntertainmentContentBrowser" }, + { 0x0c, 0x01c1, "ALOnlineShoppingBrowser" }, + { 0x0c, 0x01c2, "ALSmartCardInformationHelp" }, + { 0x0c, 0x01c3, "ALMarketMonitorFinanceBrowser" }, + { 0x0c, 0x01c4, "ALCustomizedCorporateNewsBrowser" }, + { 0x0c, 0x01c5, "ALOnlineActivityBrowser" }, + { 0x0c, 0x01c6, "ALResearchSearchBrowser" }, + { 0x0c, 0x01c7, "ALAudioPlayer" }, + { 0x0c, 0x01c8, "ALMessageStatus" }, + { 0x0c, 0x01c9, "ALContactSync" }, + { 0x0c, 0x01ca, "ALNavigation" }, + { 0x0c, 0x01cb, "ALContextawareDesktopAssistant" }, + { 0x0c, 0x0200, "GenericGUIApplicationControls" }, + { 0x0c, 0x0201, "ACNew" }, + { 0x0c, 0x0202, "ACOpen" }, + { 0x0c, 0x0203, "ACClose" }, + { 0x0c, 0x0204, "ACExit" }, + { 0x0c, 0x0205, "ACMaximize" }, + { 0x0c, 0x0206, "ACMinimize" }, + { 0x0c, 0x0207, "ACSave" }, + { 0x0c, 0x0208, "ACPrint" }, + { 0x0c, 0x0209, "ACProperties" }, + { 0x0c, 0x021a, "ACUndo" }, + { 0x0c, 0x021b, "ACCopy" }, + { 0x0c, 0x021c, "ACCut" }, + { 0x0c, 0x021d, "ACPaste" }, + { 0x0c, 0x021e, "ACSelectAll" }, + { 0x0c, 0x021f, "ACFind" }, + { 0x0c, 0x0220, "ACFindandReplace" }, + { 0x0c, 0x0221, "ACSearch" }, + { 0x0c, 0x0222, "ACGoTo" }, + { 0x0c, 0x0223, "ACHome" }, + { 0x0c, 0x0224, "ACBack" }, + { 0x0c, 0x0225, "ACForward" }, + { 0x0c, 0x0226, "ACStop" }, + { 0x0c, 0x0227, "ACRefresh" }, + { 0x0c, 0x0228, "ACPreviousLink" }, + { 0x0c, 0x0229, "ACNextLink" }, + { 0x0c, 0x022a, "ACBookmarks" }, + { 0x0c, 0x022b, "ACHistory" }, + { 0x0c, 0x022c, "ACSubscriptions" }, + { 0x0c, 0x022d, "ACZoomIn" }, + { 0x0c, 0x022e, "ACZoomOut" }, + { 0x0c, 0x022f, "ACZoom" }, + { 0x0c, 0x0230, "ACFullScreenView" }, + { 0x0c, 0x0231, "ACNormalView" }, + { 0x0c, 0x0232, "ACViewToggle" }, + { 0x0c, 0x0233, "ACScrollUp" }, + { 0x0c, 0x0234, "ACScrollDown" }, + { 0x0c, 0x0235, "ACScroll" }, + { 0x0c, 0x0236, "ACPanLeft" }, + { 0x0c, 0x0237, "ACPanRight" }, + { 0x0c, 0x0238, "ACPan" }, + { 0x0c, 0x0239, "ACNewWindow" }, + { 0x0c, 0x023a, "ACTileHorizontally" }, + { 0x0c, 0x023b, "ACTileVertically" }, + { 0x0c, 0x023c, "ACFormat" }, + { 0x0c, 0x023d, "ACEdit" }, + { 0x0c, 0x023e, "ACBold" }, + { 0x0c, 0x023f, "ACItalics" }, + { 0x0c, 0x0240, "ACUnderline" }, + { 0x0c, 0x0241, "ACStrikethrough" }, + { 0x0c, 0x0242, "ACSubscript" }, + { 0x0c, 0x0243, "ACSuperscript" }, + { 0x0c, 0x0244, "ACAllCaps" }, + { 0x0c, 0x0245, "ACRotate" }, + { 0x0c, 0x0246, "ACResize" }, + { 0x0c, 0x0247, "ACFlipHorizontal" }, + { 0x0c, 0x0248, "ACFlipVertical" }, + { 0x0c, 0x0249, "ACMirrorHorizontal" }, + { 0x0c, 0x024a, "ACMirrorVertical" }, + { 0x0c, 0x024b, "ACFontSelect" }, + { 0x0c, 0x024c, "ACFontColor" }, + { 0x0c, 0x024d, "ACFontSize" }, + { 0x0c, 0x024e, "ACJustifyLeft" }, + { 0x0c, 0x024f, "ACJustifyCenterH" }, + { 0x0c, 0x0250, "ACJustifyRight" }, + { 0x0c, 0x0251, "ACJustifyBlockH" }, + { 0x0c, 0x0252, "ACJustifyTop" }, + { 0x0c, 0x0253, "ACJustifyCenterV" }, + { 0x0c, 0x0254, "ACJustifyBottom" }, + { 0x0c, 0x0255, "ACJustifyBlockV" }, + { 0x0c, 0x0256, "ACIndentDecrease" }, + { 0x0c, 0x0257, "ACIndentIncrease" }, + { 0x0c, 0x0258, "ACNumberedList" }, + { 0x0c, 0x0259, "ACRestartNumbering" }, + { 0x0c, 0x025a, "ACBulletedList" }, + { 0x0c, 0x025b, "ACPromote" }, + { 0x0c, 0x025c, "ACDemote" }, + { 0x0c, 0x025d, "ACYes" }, + { 0x0c, 0x025e, "ACNo" }, + { 0x0c, 0x025f, "ACCancel" }, + { 0x0c, 0x0260, "ACCatalog" }, + { 0x0c, 0x0261, "ACBuyCheckout" }, + { 0x0c, 0x0262, "ACAddtoCart" }, + { 0x0c, 0x0263, "ACExpand" }, + { 0x0c, 0x0264, "ACExpandAll" }, + { 0x0c, 0x0265, "ACCollapse" }, + { 0x0c, 0x0266, "ACCollapseAll" }, + { 0x0c, 0x0267, "ACPrintPreview" }, + { 0x0c, 0x0268, "ACPasteSpecial" }, + { 0x0c, 0x0269, "ACInsertMode" }, + { 0x0c, 0x026a, "ACDelete" }, + { 0x0c, 0x026b, "ACLock" }, + { 0x0c, 0x026c, "ACUnlock" }, + { 0x0c, 0x026d, "ACProtect" }, + { 0x0c, 0x026e, "ACUnprotect" }, + { 0x0c, 0x026f, "ACAttachComment" }, + { 0x0c, 0x0270, "ACDeleteComment" }, + { 0x0c, 0x0271, "ACViewComment" }, + { 0x0c, 0x0272, "ACSelectWord" }, + { 0x0c, 0x0273, "ACSelectSentence" }, + { 0x0c, 0x0274, "ACSelectParagraph" }, + { 0x0c, 0x0275, "ACSelectColumn" }, + { 0x0c, 0x0276, "ACSelectRow" }, + { 0x0c, 0x0277, "ACSelectTable" }, + { 0x0c, 0x0278, "ACSelectObject" }, + { 0x0c, 0x0279, "ACRedoRepeat" }, + { 0x0c, 0x027a, "ACSort" }, + { 0x0c, 0x027b, "ACSortAscending" }, + { 0x0c, 0x027c, "ACSortDescending" }, + { 0x0c, 0x027d, "ACFilter" }, + { 0x0c, 0x027e, "ACSetClock" }, + { 0x0c, 0x027f, "ACViewClock" }, + { 0x0c, 0x0280, "ACSelectTimeZone" }, + { 0x0c, 0x0281, "ACEditTimeZones" }, + { 0x0c, 0x0282, "ACSetAlarm" }, + { 0x0c, 0x0283, "ACClearAlarm" }, + { 0x0c, 0x0284, "ACSnoozeAlarm" }, + { 0x0c, 0x0285, "ACResetAlarm" }, + { 0x0c, 0x0286, "ACSynchronize" }, + { 0x0c, 0x0287, "ACSendReceive" }, + { 0x0c, 0x0288, "ACSendTo" }, + { 0x0c, 0x0289, "ACReply" }, + { 0x0c, 0x028a, "ACReplyAll" }, + { 0x0c, 0x028b, "ACForwardMsg" }, + { 0x0c, 0x028c, "ACSend" }, + { 0x0c, 0x028d, "ACAttachFile" }, + { 0x0c, 0x028e, "ACUpload" }, + { 0x0c, 0x028f, "ACDownloadSaveTargetAs" }, + { 0x0c, 0x0290, "ACSetBorders" }, + { 0x0c, 0x0291, "ACInsertRow" }, + { 0x0c, 0x0292, "ACInsertColumn" }, + { 0x0c, 0x0293, "ACInsertFile" }, + { 0x0c, 0x0294, "ACInsertPicture" }, + { 0x0c, 0x0295, "ACInsertObject" }, + { 0x0c, 0x0296, "ACInsertSymbol" }, + { 0x0c, 0x0297, "ACSaveandClose" }, + { 0x0c, 0x0298, "ACRename" }, + { 0x0c, 0x0299, "ACMerge" }, + { 0x0c, 0x029a, "ACSplit" }, + { 0x0c, 0x029b, "ACDisributeHorizontally" }, + { 0x0c, 0x029c, "ACDistributeVertically" }, + { 0x0c, 0x029d, "ACNextKeyboardLayoutSelect" }, + { 0x0c, 0x029e, "ACNavigationGuidance" }, + { 0x0c, 0x029f, "ACDesktopShowAllWindows" }, + { 0x0c, 0x02a0, "ACSoftKeyLeft" }, + { 0x0c, 0x02a1, "ACSoftKeyRight" }, + { 0x0c, 0x02a2, "ACDesktopShowAllApplications" }, + { 0x0c, 0x02b0, "ACIdleKeepAlive" }, + { 0x0c, 0x02c0, "ExtendedKeyboardAttributesCollection" }, + { 0x0c, 0x02c1, "KeyboardFormFactor" }, + { 0x0c, 0x02c2, "KeyboardKeyType" }, + { 0x0c, 0x02c3, "KeyboardPhysicalLayout" }, + { 0x0c, 0x02c4, "VendorSpecificKeyboardPhysicalLayout" }, + { 0x0c, 0x02c5, "KeyboardIETFLanguageTagIndex" }, + { 0x0c, 0x02c6, "ImplementedKeyboardInputAssistControls" }, + { 0x0c, 0x02c7, "KeyboardInputAssistPrevious" }, + { 0x0c, 0x02c8, "KeyboardInputAssistNext" }, + { 0x0c, 0x02c9, "KeyboardInputAssistPreviousGroup" }, + { 0x0c, 0x02ca, "KeyboardInputAssistNextGroup" }, + { 0x0c, 0x02cb, "KeyboardInputAssistAccept" }, + { 0x0c, 0x02cc, "KeyboardInputAssistCancel" }, + { 0x0c, 0x02d0, "PrivacyScreenToggle" }, + { 0x0c, 0x02d1, "PrivacyScreenLevelDecrement" }, + { 0x0c, 0x02d2, "PrivacyScreenLevelIncrement" }, + { 0x0c, 0x02d3, "PrivacyScreenLevelMinimum" }, + { 0x0c, 0x02d4, "PrivacyScreenLevelMaximum" }, + { 0x0c, 0x0500, "ContactEdited" }, + { 0x0c, 0x0501, "ContactAdded" }, + { 0x0c, 0x0502, "ContactRecordActive" }, + { 0x0c, 0x0503, "ContactIndex" }, + { 0x0c, 0x0504, "ContactNickname" }, + { 0x0c, 0x0505, "ContactFirstName" }, + { 0x0c, 0x0506, "ContactLastName" }, + { 0x0c, 0x0507, "ContactFullName" }, + { 0x0c, 0x0508, "ContactPhoneNumberPersonal" }, + { 0x0c, 0x0509, "ContactPhoneNumberBusiness" }, + { 0x0c, 0x050a, "ContactPhoneNumberMobile" }, + { 0x0c, 0x050b, "ContactPhoneNumberPager" }, + { 0x0c, 0x050c, "ContactPhoneNumberFax" }, + { 0x0c, 0x050d, "ContactPhoneNumberOther" }, + { 0x0c, 0x050e, "ContactEmailPersonal" }, + { 0x0c, 0x050f, "ContactEmailBusiness" }, + { 0x0c, 0x0510, "ContactEmailOther" }, + { 0x0c, 0x0511, "ContactEmailMain" }, + { 0x0c, 0x0512, "ContactSpeedDialNumber" }, + { 0x0c, 0x0513, "ContactStatusFlag" }, + { 0x0c, 0x0514, "ContactMisc" }, + { 0x0d, 0, "Digitizers" }, + { 0x0d, 0x0001, "Digitizer" }, + { 0x0d, 0x0002, "Pen" }, + { 0x0d, 0x0003, "LightPen" }, + { 0x0d, 0x0004, "TouchScreen" }, + { 0x0d, 0x0005, "TouchPad" }, + { 0x0d, 0x0006, "Whiteboard" }, + { 0x0d, 0x0007, "CoordinateMeasuringMachine" }, + { 0x0d, 0x0008, "3DDigitizer" }, + { 0x0d, 0x0009, "StereoPlotter" }, + { 0x0d, 0x000a, "ArticulatedArm" }, + { 0x0d, 0x000b, "Armature" }, + { 0x0d, 0x000c, "MultiplePointDigitizer" }, + { 0x0d, 0x000d, "FreeSpaceWand" }, + { 0x0d, 0x000e, "DeviceConfiguration" }, + { 0x0d, 0x000f, "CapacitiveHeatMapDigitizer" }, + { 0x0d, 0x0020, "Stylus" }, + { 0x0d, 0x0021, "Puck" }, + { 0x0d, 0x0022, "Finger" }, + { 0x0d, 0x0023, "Devicesettings" }, + { 0x0d, 0x0024, "CharacterGesture" }, + { 0x0d, 0x0030, "TipPressure" }, + { 0x0d, 0x0031, "BarrelPressure" }, + { 0x0d, 0x0032, "InRange" }, + { 0x0d, 0x0033, "Touch" }, + { 0x0d, 0x0034, "Untouch" }, + { 0x0d, 0x0035, "Tap" }, + { 0x0d, 0x0036, "Quality" }, + { 0x0d, 0x0037, "DataValid" }, + { 0x0d, 0x0038, "TransducerIndex" }, + { 0x0d, 0x0039, "TabletFunctionKeys" }, + { 0x0d, 0x003a, "ProgramChangeKeys" }, + { 0x0d, 0x003b, "BatteryStrength" }, + { 0x0d, 0x003c, "Invert" }, + { 0x0d, 0x003d, "XTilt" }, + { 0x0d, 0x003e, "YTilt" }, + { 0x0d, 0x003f, "Azimuth" }, + { 0x0d, 0x0040, "Altitude" }, + { 0x0d, 0x0041, "Twist" }, + { 0x0d, 0x0042, "TipSwitch" }, + { 0x0d, 0x0043, "SecondaryTipSwitch" }, + { 0x0d, 0x0044, "BarrelSwitch" }, + { 0x0d, 0x0045, "Eraser" }, + { 0x0d, 0x0046, "TabletPick" }, + { 0x0d, 0x0047, "TouchValid" }, + { 0x0d, 0x0048, "Width" }, + { 0x0d, 0x0049, "Height" }, + { 0x0d, 0x0051, "ContactIdentifier" }, + { 0x0d, 0x0052, "DeviceMode" }, + { 0x0d, 0x0053, "DeviceIdentifier" }, + { 0x0d, 0x0054, "ContactCount" }, + { 0x0d, 0x0055, "ContactCountMaximum" }, + { 0x0d, 0x0056, "ScanTime" }, + { 0x0d, 0x0057, "SurfaceSwitch" }, + { 0x0d, 0x0058, "ButtonSwitch" }, + { 0x0d, 0x0059, "PadType" }, + { 0x0d, 0x005a, "SecondaryBarrelSwitch" }, + { 0x0d, 0x005b, "TransducerSerialNumber" }, + { 0x0d, 0x005c, "PreferredColor" }, + { 0x0d, 0x005d, "PreferredColorisLocked" }, + { 0x0d, 0x005e, "PreferredLineWidth" }, + { 0x0d, 0x005f, "PreferredLineWidthisLocked" }, + { 0x0d, 0x0060, "LatencyMode" }, + { 0x0d, 0x0061, "GestureCharacterQuality" }, + { 0x0d, 0x0062, "CharacterGestureDataLength" }, + { 0x0d, 0x0063, "CharacterGestureData" }, + { 0x0d, 0x0064, "GestureCharacterEncoding" }, + { 0x0d, 0x0065, "UTF8CharacterGestureEncoding" }, + { 0x0d, 0x0066, "UTF16LittleEndianCharacterGestureEncoding" }, + { 0x0d, 0x0067, "UTF16BigEndianCharacterGestureEncoding" }, + { 0x0d, 0x0068, "UTF32LittleEndianCharacterGestureEncoding" }, + { 0x0d, 0x0069, "UTF32BigEndianCharacterGestureEncoding" }, + { 0x0d, 0x006a, "CapacitiveHeatMapProtocolVendorID" }, + { 0x0d, 0x006b, "CapacitiveHeatMapProtocolVersion" }, + { 0x0d, 0x006c, "CapacitiveHeatMapFrameData" }, + { 0x0d, 0x006d, "GestureCharacterEnable" }, + { 0x0d, 0x006e, "TransducerSerialNumberPart2" }, + { 0x0d, 0x006f, "NoPreferredColor" }, + { 0x0d, 0x0070, "PreferredLineStyle" }, + { 0x0d, 0x0071, "PreferredLineStyleisLocked" }, + { 0x0d, 0x0072, "Ink" }, + { 0x0d, 0x0073, "Pencil" }, + { 0x0d, 0x0074, "Highlighter" }, + { 0x0d, 0x0075, "ChiselMarker" }, + { 0x0d, 0x0076, "Brush" }, + { 0x0d, 0x0077, "NoPreference" }, + { 0x0d, 0x0080, "DigitizerDiagnostic" }, + { 0x0d, 0x0081, "DigitizerError" }, + { 0x0d, 0x0082, "ErrNormalStatus" }, + { 0x0d, 0x0083, "ErrTransducersExceeded" }, + { 0x0d, 0x0084, "ErrFullTransFeaturesUnavailable" }, + { 0x0d, 0x0085, "ErrChargeLow" }, + { 0x0d, 0x0090, "TransducerSoftwareInfo" }, + { 0x0d, 0x0091, "TransducerVendorId" }, + { 0x0d, 0x0092, "TransducerProductId" }, + { 0x0d, 0x0093, "DeviceSupportedProtocols" }, + { 0x0d, 0x0094, "TransducerSupportedProtocols" }, + { 0x0d, 0x0095, "NoProtocol" }, + { 0x0d, 0x0096, "WacomAESProtocol" }, + { 0x0d, 0x0097, "USIProtocol" }, + { 0x0d, 0x0098, "MicrosoftPenProtocol" }, + { 0x0d, 0x00a0, "SupportedReportRates" }, + { 0x0d, 0x00a1, "ReportRate" }, + { 0x0d, 0x00a2, "TransducerConnected" }, + { 0x0d, 0x00a3, "SwitchDisabled" }, + { 0x0d, 0x00a4, "SwitchUnimplemented" }, + { 0x0d, 0x00a5, "TransducerSwitches" }, + { 0x0d, 0x00a6, "TransducerIndexSelector" }, + { 0x0d, 0x00b0, "ButtonPressThreshold" }, + { 0x0e, 0, "Haptics" }, + { 0x0e, 0x0001, "SimpleHapticController" }, + { 0x0e, 0x0010, "WaveformList" }, + { 0x0e, 0x0011, "DurationList" }, + { 0x0e, 0x0020, "AutoTrigger" }, + { 0x0e, 0x0021, "ManualTrigger" }, + { 0x0e, 0x0022, "AutoTriggerAssociatedControl" }, + { 0x0e, 0x0023, "Intensity" }, + { 0x0e, 0x0024, "RepeatCount" }, + { 0x0e, 0x0025, "RetriggerPeriod" }, + { 0x0e, 0x0026, "WaveformVendorPage" }, + { 0x0e, 0x0027, "WaveformVendorID" }, + { 0x0e, 0x0028, "WaveformCutoffTime" }, + { 0x0e, 0x1001, "WaveformNone" }, + { 0x0e, 0x1002, "WaveformStop" }, + { 0x0e, 0x1003, "WaveformClick" }, + { 0x0e, 0x1004, "WaveformBuzzContinuous" }, + { 0x0e, 0x1005, "WaveformRumbleContinuous" }, + { 0x0e, 0x1006, "WaveformPress" }, + { 0x0e, 0x1007, "WaveformRelease" }, + { 0x0e, 0x1008, "WaveformHover" }, + { 0x0e, 0x1009, "WaveformSuccess" }, + { 0x0e, 0x100a, "WaveformError" }, + { 0x0e, 0x100b, "WaveformInkContinuous" }, + { 0x0e, 0x100c, "WaveformPencilContinuous" }, + { 0x0e, 0x100d, "WaveformMarkerContinuous" }, + { 0x0e, 0x100e, "WaveformChiselMarkerContinuous" }, + { 0x0e, 0x100f, "WaveformBrushContinuous" }, + { 0x0e, 0x1010, "WaveformEraserContinuous" }, + { 0x0e, 0x1011, "WaveformSparkleContinuous" }, + { 0x0f, 0, "PhysicalInputDevice" }, + { 0x0f, 0x0001, "PhysicalInputDevice" }, + { 0x0f, 0x0020, "Normal" }, + { 0x0f, 0x0021, "SetEffectReport" }, + { 0x0f, 0x0022, "EffectParameterBlockIndex" }, + { 0x0f, 0x0023, "ParameterBlockOffset" }, + { 0x0f, 0x0024, "ROMFlag" }, + { 0x0f, 0x0025, "EffectType" }, + { 0x0f, 0x0026, "ETConstantForce" }, + { 0x0f, 0x0027, "ETRamp" }, + { 0x0f, 0x0028, "ETCustomForce" }, + { 0x0f, 0x0030, "ETSquare" }, + { 0x0f, 0x0031, "ETSine" }, + { 0x0f, 0x0032, "ETTriangle" }, + { 0x0f, 0x0033, "ETSawtoothUp" }, + { 0x0f, 0x0034, "ETSawtoothDown" }, + { 0x0f, 0x0040, "ETSpring" }, + { 0x0f, 0x0041, "ETDamper" }, + { 0x0f, 0x0042, "ETInertia" }, + { 0x0f, 0x0043, "ETFriction" }, + { 0x0f, 0x0050, "Duration" }, + { 0x0f, 0x0051, "SamplePeriod" }, + { 0x0f, 0x0052, "Gain" }, + { 0x0f, 0x0053, "TriggerButton" }, + { 0x0f, 0x0054, "TriggerRepeatInterval" }, + { 0x0f, 0x0055, "AxesEnable" }, + { 0x0f, 0x0056, "DirectionEnable" }, + { 0x0f, 0x0057, "Direction" }, + { 0x0f, 0x0058, "TypeSpecificBlockOffset" }, + { 0x0f, 0x0059, "BlockType" }, + { 0x0f, 0x005a, "SetEnvelopeReport" }, + { 0x0f, 0x005b, "AttackLevel" }, + { 0x0f, 0x005c, "AttackTime" }, + { 0x0f, 0x005d, "FadeLevel" }, + { 0x0f, 0x005e, "FadeTime" }, + { 0x0f, 0x005f, "SetConditionReport" }, + { 0x0f, 0x0060, "CenterPointOffset" }, + { 0x0f, 0x0061, "PositiveCoefficient" }, + { 0x0f, 0x0062, "NegativeCoefficient" }, + { 0x0f, 0x0063, "PositiveSaturation" }, + { 0x0f, 0x0064, "NegativeSaturation" }, + { 0x0f, 0x0065, "DeadBand" }, + { 0x0f, 0x0066, "DownloadForceSample" }, + { 0x0f, 0x0067, "IsochCustomForceEnable" }, + { 0x0f, 0x0068, "CustomForceDataReport" }, + { 0x0f, 0x0069, "CustomForceData" }, + { 0x0f, 0x006a, "CustomForceVendorDefinedData" }, + { 0x0f, 0x006b, "SetCustomForceReport" }, + { 0x0f, 0x006c, "CustomForceDataOffset" }, + { 0x0f, 0x006d, "SampleCount" }, + { 0x0f, 0x006e, "SetPeriodicReport" }, + { 0x0f, 0x006f, "Offset" }, + { 0x0f, 0x0070, "Magnitude" }, + { 0x0f, 0x0071, "Phase" }, + { 0x0f, 0x0072, "Period" }, + { 0x0f, 0x0073, "SetConstantForceReport" }, + { 0x0f, 0x0074, "SetRampForceReport" }, + { 0x0f, 0x0075, "RampStart" }, + { 0x0f, 0x0076, "RampEnd" }, + { 0x0f, 0x0077, "EffectOperationReport" }, + { 0x0f, 0x0078, "EffectOperation" }, + { 0x0f, 0x0079, "OpEffectStart" }, + { 0x0f, 0x007a, "OpEffectStartSolo" }, + { 0x0f, 0x007b, "OpEffectStop" }, + { 0x0f, 0x007c, "LoopCount" }, + { 0x0f, 0x007d, "DeviceGainReport" }, + { 0x0f, 0x007e, "DeviceGain" }, + { 0x0f, 0x007f, "ParameterBlockPoolsReport" }, + { 0x0f, 0x0080, "RAMPoolSize" }, + { 0x0f, 0x0081, "ROMPoolSize" }, + { 0x0f, 0x0082, "ROMEffectBlockCount" }, + { 0x0f, 0x0083, "SimultaneousEffectsMax" }, + { 0x0f, 0x0084, "PoolAlignment" }, + { 0x0f, 0x0085, "ParameterBlockMoveReport" }, + { 0x0f, 0x0086, "MoveSource" }, + { 0x0f, 0x0087, "MoveDestination" }, + { 0x0f, 0x0088, "MoveLength" }, + { 0x0f, 0x0089, "EffectParameterBlockLoadReport" }, + { 0x0f, 0x008b, "EffectParameterBlockLoadStatus" }, + { 0x0f, 0x008c, "BlockLoadSuccess" }, + { 0x0f, 0x008d, "BlockLoadFull" }, + { 0x0f, 0x008e, "BlockLoadError" }, + { 0x0f, 0x008f, "BlockHandle" }, + { 0x0f, 0x0090, "EffectParameterBlockFreeReport" }, + { 0x0f, 0x0091, "TypeSpecificBlockHandle" }, + { 0x0f, 0x0092, "PIDStateReport" }, + { 0x0f, 0x0094, "EffectPlaying" }, + { 0x0f, 0x0095, "PIDDeviceControlReport" }, + { 0x0f, 0x0096, "PIDDeviceControl" }, + { 0x0f, 0x0097, "DCEnableActuators" }, + { 0x0f, 0x0098, "DCDisableActuators" }, + { 0x0f, 0x0099, "DCStopAllEffects" }, + { 0x0f, 0x009a, "DCReset" }, + { 0x0f, 0x009b, "DCPause" }, + { 0x0f, 0x009c, "DCContinue" }, + { 0x0f, 0x009f, "DevicePaused" }, + { 0x0f, 0x00a0, "ActuatorsEnabled" }, + { 0x0f, 0x00a4, "SafetySwitch" }, + { 0x0f, 0x00a5, "ActuatorOverrideSwitch" }, + { 0x0f, 0x00a6, "ActuatorPower" }, + { 0x0f, 0x00a7, "StartDelay" }, + { 0x0f, 0x00a8, "ParameterBlockSize" }, + { 0x0f, 0x00a9, "DeviceManagedPool" }, + { 0x0f, 0x00aa, "SharedParameterBlocks" }, + { 0x0f, 0x00ab, "CreateNewEffectParameterBlockReport" }, + { 0x0f, 0x00ac, "RAMPoolAvailable" }, + { 0x11, 0, "SoC" }, + { 0x11, 0x0001, "SocControl" }, + { 0x11, 0x0002, "FirmwareTransfer" }, + { 0x11, 0x0003, "FirmwareFileId" }, + { 0x11, 0x0004, "FileOffsetInBytes" }, + { 0x11, 0x0005, "FileTransferSizeMaxInBytes" }, + { 0x11, 0x0006, "FilePayload" }, + { 0x11, 0x0007, "FilePayloadSizeInBytes" }, + { 0x11, 0x0008, "FilePayloadContainsLastBytes" }, + { 0x11, 0x0009, "FileTransferStop" }, + { 0x11, 0x000a, "FileTransferTillEnd" }, + { 0x12, 0, "EyeandHeadTrackers" }, + { 0x12, 0x0001, "EyeTracker" }, + { 0x12, 0x0002, "HeadTracker" }, + { 0x12, 0x0010, "TrackingData" }, + { 0x12, 0x0011, "Capabilities" }, + { 0x12, 0x0012, "Configuration" }, + { 0x12, 0x0013, "Status" }, + { 0x12, 0x0014, "Control" }, + { 0x12, 0x0020, "SensorTimestamp" }, + { 0x12, 0x0021, "PositionX" }, + { 0x12, 0x0022, "PositionY" }, + { 0x12, 0x0023, "PositionZ" }, + { 0x12, 0x0024, "GazePoint" }, + { 0x12, 0x0025, "LeftEyePosition" }, + { 0x12, 0x0026, "RightEyePosition" }, + { 0x12, 0x0027, "HeadPosition" }, + { 0x12, 0x0028, "HeadDirectionPoint" }, + { 0x12, 0x0029, "RotationaboutXaxis" }, + { 0x12, 0x002a, "RotationaboutYaxis" }, + { 0x12, 0x002b, "RotationaboutZaxis" }, + { 0x12, 0x0100, "TrackerQuality" }, + { 0x12, 0x0101, "MinimumTrackingDistance" }, + { 0x12, 0x0102, "OptimumTrackingDistance" }, + { 0x12, 0x0103, "MaximumTrackingDistance" }, + { 0x12, 0x0104, "MaximumScreenPlaneWidth" }, + { 0x12, 0x0105, "MaximumScreenPlaneHeight" }, + { 0x12, 0x0200, "DisplayManufacturerID" }, + { 0x12, 0x0201, "DisplayProductID" }, + { 0x12, 0x0202, "DisplaySerialNumber" }, + { 0x12, 0x0203, "DisplayManufacturerDate" }, + { 0x12, 0x0204, "CalibratedScreenWidth" }, + { 0x12, 0x0205, "CalibratedScreenHeight" }, + { 0x12, 0x0300, "SamplingFrequency" }, + { 0x12, 0x0301, "ConfigurationStatus" }, + { 0x12, 0x0400, "DeviceModeRequest" }, + { 0x14, 0, "AuxiliaryDisplay" }, + { 0x14, 0x0001, "AlphanumericDisplay" }, + { 0x14, 0x0002, "AuxiliaryDisplay" }, + { 0x14, 0x0020, "DisplayAttributesReport" }, + { 0x14, 0x0021, "ASCIICharacterSet" }, + { 0x14, 0x0022, "DataReadBack" }, + { 0x14, 0x0023, "FontReadBack" }, + { 0x14, 0x0024, "DisplayControlReport" }, + { 0x14, 0x0025, "ClearDisplay" }, + { 0x14, 0x0026, "DisplayEnable" }, + { 0x14, 0x0027, "ScreenSaverDelay" }, + { 0x14, 0x0028, "ScreenSaverEnable" }, + { 0x14, 0x0029, "VerticalScroll" }, + { 0x14, 0x002a, "HorizontalScroll" }, + { 0x14, 0x002b, "CharacterReport" }, + { 0x14, 0x002c, "DisplayData" }, + { 0x14, 0x002d, "DisplayStatus" }, + { 0x14, 0x002e, "StatNotReady" }, + { 0x14, 0x002f, "StatReady" }, + { 0x14, 0x0030, "ErrNotaloadablecharacter" }, + { 0x14, 0x0031, "ErrFontdatacannotberead" }, + { 0x14, 0x0032, "CursorPositionReport" }, + { 0x14, 0x0033, "Row" }, + { 0x14, 0x0034, "Column" }, + { 0x14, 0x0035, "Rows" }, + { 0x14, 0x0036, "Columns" }, + { 0x14, 0x0037, "CursorPixelPositioning" }, + { 0x14, 0x0038, "CursorMode" }, + { 0x14, 0x0039, "CursorEnable" }, + { 0x14, 0x003a, "CursorBlink" }, + { 0x14, 0x003b, "FontReport" }, + { 0x14, 0x003c, "FontData" }, + { 0x14, 0x003d, "CharacterWidth" }, + { 0x14, 0x003e, "CharacterHeight" }, + { 0x14, 0x003f, "CharacterSpacingHorizontal" }, + { 0x14, 0x0040, "CharacterSpacingVertical" }, + { 0x14, 0x0041, "UnicodeCharacterSet" }, + { 0x14, 0x0042, "Font7Segment" }, + { 0x14, 0x0043, "7SegmentDirectMap" }, + { 0x14, 0x0044, "Font14Segment" }, + { 0x14, 0x0045, "14SegmentDirectMap" }, + { 0x14, 0x0046, "DisplayBrightness" }, + { 0x14, 0x0047, "DisplayContrast" }, + { 0x14, 0x0048, "CharacterAttribute" }, + { 0x14, 0x0049, "AttributeReadback" }, + { 0x14, 0x004a, "AttributeData" }, + { 0x14, 0x004b, "CharAttrEnhance" }, + { 0x14, 0x004c, "CharAttrUnderline" }, + { 0x14, 0x004d, "CharAttrBlink" }, + { 0x14, 0x0080, "BitmapSizeX" }, + { 0x14, 0x0081, "BitmapSizeY" }, + { 0x14, 0x0082, "MaxBlitSize" }, + { 0x14, 0x0083, "BitDepthFormat" }, + { 0x14, 0x0084, "DisplayOrientation" }, + { 0x14, 0x0085, "PaletteReport" }, + { 0x14, 0x0086, "PaletteDataSize" }, + { 0x14, 0x0087, "PaletteDataOffset" }, + { 0x14, 0x0088, "PaletteData" }, + { 0x14, 0x008a, "BlitReport" }, + { 0x14, 0x008b, "BlitRectangleX1" }, + { 0x14, 0x008c, "BlitRectangleY1" }, + { 0x14, 0x008d, "BlitRectangleX2" }, + { 0x14, 0x008e, "BlitRectangleY2" }, + { 0x14, 0x008f, "BlitData" }, + { 0x14, 0x0090, "SoftButton" }, + { 0x14, 0x0091, "SoftButtonID" }, + { 0x14, 0x0092, "SoftButtonSide" }, + { 0x14, 0x0093, "SoftButtonOffset1" }, + { 0x14, 0x0094, "SoftButtonOffset2" }, + { 0x14, 0x0095, "SoftButtonReport" }, + { 0x14, 0x00c2, "SoftKeys" }, + { 0x14, 0x00cc, "DisplayDataExtensions" }, + { 0x14, 0x00cf, "CharacterMapping" }, + { 0x14, 0x00dd, "UnicodeEquivalent" }, + { 0x14, 0x00df, "CharacterPageMapping" }, + { 0x14, 0x00ff, "RequestReport" }, + { 0x20, 0, "Sensors" }, + { 0x20, 0x0001, "Sensor" }, + { 0x20, 0x0010, "Biometric" }, + { 0x20, 0x0011, "BiometricHumanPresence" }, + { 0x20, 0x0012, "BiometricHumanProximity" }, + { 0x20, 0x0013, "BiometricHumanTouch" }, + { 0x20, 0x0014, "BiometricBloodPressure" }, + { 0x20, 0x0015, "BiometricBodyTemperature" }, + { 0x20, 0x0016, "BiometricHeartRate" }, + { 0x20, 0x0017, "BiometricHeartRateVariability" }, + { 0x20, 0x0018, "BiometricPeripheralOxygenSaturation" }, + { 0x20, 0x0019, "BiometricRespiratoryRate" }, + { 0x20, 0x0020, "Electrical" }, + { 0x20, 0x0021, "ElectricalCapacitance" }, + { 0x20, 0x0022, "ElectricalCurrent" }, + { 0x20, 0x0023, "ElectricalPower" }, + { 0x20, 0x0024, "ElectricalInductance" }, + { 0x20, 0x0025, "ElectricalResistance" }, + { 0x20, 0x0026, "ElectricalVoltage" }, + { 0x20, 0x0027, "ElectricalPotentiometer" }, + { 0x20, 0x0028, "ElectricalFrequency" }, + { 0x20, 0x0029, "ElectricalPeriod" }, + { 0x20, 0x0030, "Environmental" }, + { 0x20, 0x0031, "EnvironmentalAtmosphericPressure" }, + { 0x20, 0x0032, "EnvironmentalHumidity" }, + { 0x20, 0x0033, "EnvironmentalTemperature" }, + { 0x20, 0x0034, "EnvironmentalWindDirection" }, + { 0x20, 0x0035, "EnvironmentalWindSpeed" }, + { 0x20, 0x0036, "EnvironmentalAirQuality" }, + { 0x20, 0x0037, "EnvironmentalHeatIndex" }, + { 0x20, 0x0038, "EnvironmentalSurfaceTemperature" }, + { 0x20, 0x0039, "EnvironmentalVolatileOrganicCompounds" }, + { 0x20, 0x003a, "EnvironmentalObjectPresence" }, + { 0x20, 0x003b, "EnvironmentalObjectProximity" }, + { 0x20, 0x0040, "Light" }, + { 0x20, 0x0041, "LightAmbientLight" }, + { 0x20, 0x0042, "LightConsumerInfrared" }, + { 0x20, 0x0043, "LightInfraredLight" }, + { 0x20, 0x0044, "LightVisibleLight" }, + { 0x20, 0x0045, "LightUltravioletLight" }, + { 0x20, 0x0050, "Location" }, + { 0x20, 0x0051, "LocationBroadcast" }, + { 0x20, 0x0052, "LocationDeadReckoning" }, + { 0x20, 0x0053, "LocationGPSGlobalPositioningSystem" }, + { 0x20, 0x0054, "LocationLookup" }, + { 0x20, 0x0055, "LocationOther" }, + { 0x20, 0x0056, "LocationStatic" }, + { 0x20, 0x0057, "LocationTriangulation" }, + { 0x20, 0x0060, "Mechanical" }, + { 0x20, 0x0061, "MechanicalBooleanSwitch" }, + { 0x20, 0x0062, "MechanicalBooleanSwitchArray" }, + { 0x20, 0x0063, "MechanicalMultivalueSwitch" }, + { 0x20, 0x0064, "MechanicalForce" }, + { 0x20, 0x0065, "MechanicalPressure" }, + { 0x20, 0x0066, "MechanicalStrain" }, + { 0x20, 0x0067, "MechanicalWeight" }, + { 0x20, 0x0068, "MechanicalHapticVibrator" }, + { 0x20, 0x0069, "MechanicalHallEffectSwitch" }, + { 0x20, 0x0070, "Motion" }, + { 0x20, 0x0071, "MotionAccelerometer1D" }, + { 0x20, 0x0072, "MotionAccelerometer2D" }, + { 0x20, 0x0073, "MotionAccelerometer3D" }, + { 0x20, 0x0074, "MotionGyrometer1D" }, + { 0x20, 0x0075, "MotionGyrometer2D" }, + { 0x20, 0x0076, "MotionGyrometer3D" }, + { 0x20, 0x0077, "MotionMotionDetector" }, + { 0x20, 0x0078, "MotionSpeedometer" }, + { 0x20, 0x0079, "MotionAccelerometer" }, + { 0x20, 0x007a, "MotionGyrometer" }, + { 0x20, 0x007b, "MotionGravityVector" }, + { 0x20, 0x007c, "MotionLinearAccelerometer" }, + { 0x20, 0x0080, "Orientation" }, + { 0x20, 0x0081, "OrientationCompass1D" }, + { 0x20, 0x0082, "OrientationCompass2D" }, + { 0x20, 0x0083, "OrientationCompass3D" }, + { 0x20, 0x0084, "OrientationInclinometer1D" }, + { 0x20, 0x0085, "OrientationInclinometer2D" }, + { 0x20, 0x0086, "OrientationInclinometer3D" }, + { 0x20, 0x0087, "OrientationDistance1D" }, + { 0x20, 0x0088, "OrientationDistance2D" }, + { 0x20, 0x0089, "OrientationDistance3D" }, + { 0x20, 0x008a, "OrientationDeviceOrientation" }, + { 0x20, 0x008b, "OrientationCompass" }, + { 0x20, 0x008c, "OrientationInclinometer" }, + { 0x20, 0x008d, "OrientationDistance" }, + { 0x20, 0x008e, "OrientationRelativeOrientation" }, + { 0x20, 0x008f, "OrientationSimpleOrientation" }, + { 0x20, 0x0090, "Scanner" }, + { 0x20, 0x0091, "ScannerBarcode" }, + { 0x20, 0x0092, "ScannerRFID" }, + { 0x20, 0x0093, "ScannerNFC" }, + { 0x20, 0x00a0, "Time" }, + { 0x20, 0x00a1, "TimeAlarmTimer" }, + { 0x20, 0x00a2, "TimeRealTimeClock" }, + { 0x20, 0x00b0, "PersonalActivity" }, + { 0x20, 0x00b1, "PersonalActivityActivityDetection" }, + { 0x20, 0x00b2, "PersonalActivityDevicePosition" }, + { 0x20, 0x00b3, "PersonalActivityFloorTracker" }, + { 0x20, 0x00b4, "PersonalActivityPedometer" }, + { 0x20, 0x00b5, "PersonalActivityStepDetection" }, + { 0x20, 0x00c0, "OrientationExtended" }, + { 0x20, 0x00c1, "OrientationExtendedGeomagneticOrientation" }, + { 0x20, 0x00c2, "OrientationExtendedMagnetometer" }, + { 0x20, 0x00d0, "Gesture" }, + { 0x20, 0x00d1, "GestureChassisFlipGesture" }, + { 0x20, 0x00d2, "GestureHingeFoldGesture" }, + { 0x20, 0x00e0, "Other" }, + { 0x20, 0x00e1, "OtherCustom" }, + { 0x20, 0x00e2, "OtherGeneric" }, + { 0x20, 0x00e3, "OtherGenericEnumerator" }, + { 0x20, 0x00e4, "OtherHingeAngle" }, + { 0x20, 0x00f0, "VendorReserved1" }, + { 0x20, 0x00f1, "VendorReserved2" }, + { 0x20, 0x00f2, "VendorReserved3" }, + { 0x20, 0x00f3, "VendorReserved4" }, + { 0x20, 0x00f4, "VendorReserved5" }, + { 0x20, 0x00f5, "VendorReserved6" }, + { 0x20, 0x00f6, "VendorReserved7" }, + { 0x20, 0x00f7, "VendorReserved8" }, + { 0x20, 0x00f8, "VendorReserved9" }, + { 0x20, 0x00f9, "VendorReserved10" }, + { 0x20, 0x00fa, "VendorReserved11" }, + { 0x20, 0x00fb, "VendorReserved12" }, + { 0x20, 0x00fc, "VendorReserved13" }, + { 0x20, 0x00fd, "VendorReserved14" }, + { 0x20, 0x00fe, "VendorReserved15" }, + { 0x20, 0x00ff, "VendorReserved16" }, + { 0x20, 0x0200, "Event" }, + { 0x20, 0x0201, "EventSensorState" }, + { 0x20, 0x0202, "EventSensorEvent" }, + { 0x20, 0x0300, "Property" }, + { 0x20, 0x0301, "PropertyFriendlyName" }, + { 0x20, 0x0302, "PropertyPersistentUniqueID" }, + { 0x20, 0x0303, "PropertySensorStatus" }, + { 0x20, 0x0304, "PropertyMinimumReportInterval" }, + { 0x20, 0x0305, "PropertySensorManufacturer" }, + { 0x20, 0x0306, "PropertySensorModel" }, + { 0x20, 0x0307, "PropertySensorSerialNumber" }, + { 0x20, 0x0308, "PropertySensorDescription" }, + { 0x20, 0x0309, "PropertySensorConnectionType" }, + { 0x20, 0x030a, "PropertySensorDevicePath" }, + { 0x20, 0x030b, "PropertyHardwareRevision" }, + { 0x20, 0x030c, "PropertyFirmwareVersion" }, + { 0x20, 0x030d, "PropertyReleaseDate" }, + { 0x20, 0x030e, "PropertyReportInterval" }, + { 0x20, 0x030f, "PropertyChangeSensitivityAbsolute" }, + { 0x20, 0x0310, "PropertyChangeSensitivityPercentofRange" }, + { 0x20, 0x0311, "PropertyChangeSensitivityPercentRelative" }, + { 0x20, 0x0312, "PropertyAccuracy" }, + { 0x20, 0x0313, "PropertyResolution" }, + { 0x20, 0x0314, "PropertyMaximum" }, + { 0x20, 0x0315, "PropertyMinimum" }, + { 0x20, 0x0316, "PropertyReportingState" }, + { 0x20, 0x0317, "PropertySamplingRate" }, + { 0x20, 0x0318, "PropertyResponseCurve" }, + { 0x20, 0x0319, "PropertyPowerState" }, + { 0x20, 0x031a, "PropertyMaximumFIFOEvents" }, + { 0x20, 0x031b, "PropertyReportLatency" }, + { 0x20, 0x031c, "PropertyFlushFIFOEvents" }, + { 0x20, 0x031d, "PropertyMaximumPowerConsumption" }, + { 0x20, 0x031e, "PropertyIsPrimary" }, + { 0x20, 0x031f, "PropertyHumanPresenceDetectionType" }, + { 0x20, 0x0400, "DataFieldLocation" }, + { 0x20, 0x0402, "DataFieldAltitudeAntennaSeaLevel" }, + { 0x20, 0x0403, "DataFieldDifferentialReferenceStationID" }, + { 0x20, 0x0404, "DataFieldAltitudeEllipsoidError" }, + { 0x20, 0x0405, "DataFieldAltitudeEllipsoid" }, + { 0x20, 0x0406, "DataFieldAltitudeSeaLevelError" }, + { 0x20, 0x0407, "DataFieldAltitudeSeaLevel" }, + { 0x20, 0x0408, "DataFieldDifferentialGPSDataAge" }, + { 0x20, 0x0409, "DataFieldErrorRadius" }, + { 0x20, 0x040a, "DataFieldFixQuality" }, + { 0x20, 0x040b, "DataFieldFixType" }, + { 0x20, 0x040c, "DataFieldGeoidalSeparation" }, + { 0x20, 0x040d, "DataFieldGPSOperationMode" }, + { 0x20, 0x040e, "DataFieldGPSSelectionMode" }, + { 0x20, 0x040f, "DataFieldGPSStatus" }, + { 0x20, 0x0410, "DataFieldPositionDilutionofPrecision" }, + { 0x20, 0x0411, "DataFieldHorizontalDilutionofPrecision" }, + { 0x20, 0x0412, "DataFieldVerticalDilutionofPrecision" }, + { 0x20, 0x0413, "DataFieldLatitude" }, + { 0x20, 0x0414, "DataFieldLongitude" }, + { 0x20, 0x0415, "DataFieldTrueHeading" }, + { 0x20, 0x0416, "DataFieldMagneticHeading" }, + { 0x20, 0x0417, "DataFieldMagneticVariation" }, + { 0x20, 0x0418, "DataFieldSpeed" }, + { 0x20, 0x0419, "DataFieldSatellitesinView" }, + { 0x20, 0x041a, "DataFieldSatellitesinViewAzimuth" }, + { 0x20, 0x041b, "DataFieldSatellitesinViewElevation" }, + { 0x20, 0x041c, "DataFieldSatellitesinViewIDs" }, + { 0x20, 0x041d, "DataFieldSatellitesinViewPRNs" }, + { 0x20, 0x041e, "DataFieldSatellitesinViewSNRatios" }, + { 0x20, 0x041f, "DataFieldSatellitesUsedCount" }, + { 0x20, 0x0420, "DataFieldSatellitesUsedPRNs" }, + { 0x20, 0x0421, "DataFieldNMEASentence" }, + { 0x20, 0x0422, "DataFieldAddressLine1" }, + { 0x20, 0x0423, "DataFieldAddressLine2" }, + { 0x20, 0x0424, "DataFieldCity" }, + { 0x20, 0x0425, "DataFieldStateorProvince" }, + { 0x20, 0x0426, "DataFieldCountryorRegion" }, + { 0x20, 0x0427, "DataFieldPostalCode" }, + { 0x20, 0x042a, "PropertyLocation" }, + { 0x20, 0x042b, "PropertyLocationDesiredAccuracy" }, + { 0x20, 0x0430, "DataFieldEnvironmental" }, + { 0x20, 0x0431, "DataFieldAtmosphericPressure" }, + { 0x20, 0x0433, "DataFieldRelativeHumidity" }, + { 0x20, 0x0434, "DataFieldTemperature" }, + { 0x20, 0x0435, "DataFieldWindDirection" }, + { 0x20, 0x0436, "DataFieldWindSpeed" }, + { 0x20, 0x0437, "DataFieldAirQualityIndex" }, + { 0x20, 0x0438, "DataFieldEquivalentCO2" }, + { 0x20, 0x0439, "DataFieldVolatileOrganicCompoundConcentration" }, + { 0x20, 0x043a, "DataFieldObjectPresence" }, + { 0x20, 0x043b, "DataFieldObjectProximityRange" }, + { 0x20, 0x043c, "DataFieldObjectProximityOutofRange" }, + { 0x20, 0x0440, "PropertyEnvironmental" }, + { 0x20, 0x0441, "PropertyReferencePressure" }, + { 0x20, 0x0450, "DataFieldMotion" }, + { 0x20, 0x0451, "DataFieldMotionState" }, + { 0x20, 0x0452, "DataFieldAcceleration" }, + { 0x20, 0x0453, "DataFieldAccelerationAxisX" }, + { 0x20, 0x0454, "DataFieldAccelerationAxisY" }, + { 0x20, 0x0455, "DataFieldAccelerationAxisZ" }, + { 0x20, 0x0456, "DataFieldAngularVelocity" }, + { 0x20, 0x0457, "DataFieldAngularVelocityaboutXAxis" }, + { 0x20, 0x0458, "DataFieldAngularVelocityaboutYAxis" }, + { 0x20, 0x0459, "DataFieldAngularVelocityaboutZAxis" }, + { 0x20, 0x045a, "DataFieldAngularPosition" }, + { 0x20, 0x045b, "DataFieldAngularPositionaboutXAxis" }, + { 0x20, 0x045c, "DataFieldAngularPositionaboutYAxis" }, + { 0x20, 0x045d, "DataFieldAngularPositionaboutZAxis" }, + { 0x20, 0x045e, "DataFieldMotionSpeed" }, + { 0x20, 0x045f, "DataFieldMotionIntensity" }, + { 0x20, 0x0470, "DataFieldOrientation" }, + { 0x20, 0x0471, "DataFieldHeading" }, + { 0x20, 0x0472, "DataFieldHeadingXAxis" }, + { 0x20, 0x0473, "DataFieldHeadingYAxis" }, + { 0x20, 0x0474, "DataFieldHeadingZAxis" }, + { 0x20, 0x0475, "DataFieldHeadingCompensatedMagneticNorth" }, + { 0x20, 0x0476, "DataFieldHeadingCompensatedTrueNorth" }, + { 0x20, 0x0477, "DataFieldHeadingMagneticNorth" }, + { 0x20, 0x0478, "DataFieldHeadingTrueNorth" }, + { 0x20, 0x0479, "DataFieldDistance" }, + { 0x20, 0x047a, "DataFieldDistanceXAxis" }, + { 0x20, 0x047b, "DataFieldDistanceYAxis" }, + { 0x20, 0x047c, "DataFieldDistanceZAxis" }, + { 0x20, 0x047d, "DataFieldDistanceOutofRange" }, + { 0x20, 0x047e, "DataFieldTilt" }, + { 0x20, 0x047f, "DataFieldTiltXAxis" }, + { 0x20, 0x0480, "DataFieldTiltYAxis" }, + { 0x20, 0x0481, "DataFieldTiltZAxis" }, + { 0x20, 0x0482, "DataFieldRotationMatrix" }, + { 0x20, 0x0483, "DataFieldQuaternion" }, + { 0x20, 0x0484, "DataFieldMagneticFlux" }, + { 0x20, 0x0485, "DataFieldMagneticFluxXAxis" }, + { 0x20, 0x0486, "DataFieldMagneticFluxYAxis" }, + { 0x20, 0x0487, "DataFieldMagneticFluxZAxis" }, + { 0x20, 0x0488, "DataFieldMagnetometerAccuracy" }, + { 0x20, 0x0489, "DataFieldSimpleOrientationDirection" }, + { 0x20, 0x0490, "DataFieldMechanical" }, + { 0x20, 0x0491, "DataFieldBooleanSwitchState" }, + { 0x20, 0x0492, "DataFieldBooleanSwitchArrayStates" }, + { 0x20, 0x0493, "DataFieldMultivalueSwitchValue" }, + { 0x20, 0x0494, "DataFieldForce" }, + { 0x20, 0x0495, "DataFieldAbsolutePressure" }, + { 0x20, 0x0496, "DataFieldGaugePressure" }, + { 0x20, 0x0497, "DataFieldStrain" }, + { 0x20, 0x0498, "DataFieldWeight" }, + { 0x20, 0x04a0, "PropertyMechanical" }, + { 0x20, 0x04a1, "PropertyVibrationState" }, + { 0x20, 0x04a2, "PropertyForwardVibrationSpeed" }, + { 0x20, 0x04a3, "PropertyBackwardVibrationSpeed" }, + { 0x20, 0x04b0, "DataFieldBiometric" }, + { 0x20, 0x04b1, "DataFieldHumanPresence" }, + { 0x20, 0x04b2, "DataFieldHumanProximityRange" }, + { 0x20, 0x04b3, "DataFieldHumanProximityOutofRange" }, + { 0x20, 0x04b4, "DataFieldHumanTouchState" }, + { 0x20, 0x04b5, "DataFieldBloodPressure" }, + { 0x20, 0x04b6, "DataFieldBloodPressureDiastolic" }, + { 0x20, 0x04b7, "DataFieldBloodPressureSystolic" }, + { 0x20, 0x04b8, "DataFieldHeartRate" }, + { 0x20, 0x04b9, "DataFieldRestingHeartRate" }, + { 0x20, 0x04ba, "DataFieldHeartbeatInterval" }, + { 0x20, 0x04bb, "DataFieldRespiratoryRate" }, + { 0x20, 0x04bc, "DataFieldSpO2" }, + { 0x20, 0x04bd, "DataFieldHumanAttentionDetected" }, + { 0x20, 0x04be, "DataFieldHumanHeadAzimuth" }, + { 0x20, 0x04bf, "DataFieldHumanHeadAltitude" }, + { 0x20, 0x04c0, "DataFieldHumanHeadRoll" }, + { 0x20, 0x04c1, "DataFieldHumanHeadPitch" }, + { 0x20, 0x04c2, "DataFieldHumanHeadYaw" }, + { 0x20, 0x04c3, "DataFieldHumanCorrelationId" }, + { 0x20, 0x04d0, "DataFieldLight" }, + { 0x20, 0x04d1, "DataFieldIlluminance" }, + { 0x20, 0x04d2, "DataFieldColorTemperature" }, + { 0x20, 0x04d3, "DataFieldChromaticity" }, + { 0x20, 0x04d4, "DataFieldChromaticityX" }, + { 0x20, 0x04d5, "DataFieldChromaticityY" }, + { 0x20, 0x04d6, "DataFieldConsumerIRSentenceReceive" }, + { 0x20, 0x04d7, "DataFieldInfraredLight" }, + { 0x20, 0x04d8, "DataFieldRedLight" }, + { 0x20, 0x04d9, "DataFieldGreenLight" }, + { 0x20, 0x04da, "DataFieldBlueLight" }, + { 0x20, 0x04db, "DataFieldUltravioletALight" }, + { 0x20, 0x04dc, "DataFieldUltravioletBLight" }, + { 0x20, 0x04dd, "DataFieldUltravioletIndex" }, + { 0x20, 0x04de, "DataFieldNearInfraredLight" }, + { 0x20, 0x04df, "PropertyLight" }, + { 0x20, 0x04e0, "PropertyConsumerIRSentenceSend" }, + { 0x20, 0x04e2, "PropertyAutoBrightnessPreferred" }, + { 0x20, 0x04e3, "PropertyAutoColorPreferred" }, + { 0x20, 0x04f0, "DataFieldScanner" }, + { 0x20, 0x04f1, "DataFieldRFIDTag40Bit" }, + { 0x20, 0x04f2, "DataFieldNFCSentenceReceive" }, + { 0x20, 0x04f8, "PropertyScanner" }, + { 0x20, 0x04f9, "PropertyNFCSentenceSend" }, + { 0x20, 0x0500, "DataFieldElectrical" }, + { 0x20, 0x0501, "DataFieldCapacitance" }, + { 0x20, 0x0502, "DataFieldCurrent" }, + { 0x20, 0x0503, "DataFieldElectricalPower" }, + { 0x20, 0x0504, "DataFieldInductance" }, + { 0x20, 0x0505, "DataFieldResistance" }, + { 0x20, 0x0506, "DataFieldVoltage" }, + { 0x20, 0x0507, "DataFieldFrequency" }, + { 0x20, 0x0508, "DataFieldPeriod" }, + { 0x20, 0x0509, "DataFieldPercentofRange" }, + { 0x20, 0x0520, "DataFieldTime" }, + { 0x20, 0x0521, "DataFieldYear" }, + { 0x20, 0x0522, "DataFieldMonth" }, + { 0x20, 0x0523, "DataFieldDay" }, + { 0x20, 0x0524, "DataFieldDayofWeek" }, + { 0x20, 0x0525, "DataFieldHour" }, + { 0x20, 0x0526, "DataFieldMinute" }, + { 0x20, 0x0527, "DataFieldSecond" }, + { 0x20, 0x0528, "DataFieldMillisecond" }, + { 0x20, 0x0529, "DataFieldTimestamp" }, + { 0x20, 0x052a, "DataFieldJulianDayofYear" }, + { 0x20, 0x052b, "DataFieldTimeSinceSystemBoot" }, + { 0x20, 0x0530, "PropertyTime" }, + { 0x20, 0x0531, "PropertyTimeZoneOffsetfromUTC" }, + { 0x20, 0x0532, "PropertyTimeZoneName" }, + { 0x20, 0x0533, "PropertyDaylightSavingsTimeObserved" }, + { 0x20, 0x0534, "PropertyTimeTrimAdjustment" }, + { 0x20, 0x0535, "PropertyArmAlarm" }, + { 0x20, 0x0540, "DataFieldCustom" }, + { 0x20, 0x0541, "DataFieldCustomUsage" }, + { 0x20, 0x0542, "DataFieldCustomBooleanArray" }, + { 0x20, 0x0543, "DataFieldCustomValue" }, + { 0x20, 0x0544, "DataFieldCustomValue1" }, + { 0x20, 0x0545, "DataFieldCustomValue2" }, + { 0x20, 0x0546, "DataFieldCustomValue3" }, + { 0x20, 0x0547, "DataFieldCustomValue4" }, + { 0x20, 0x0548, "DataFieldCustomValue5" }, + { 0x20, 0x0549, "DataFieldCustomValue6" }, + { 0x20, 0x054a, "DataFieldCustomValue7" }, + { 0x20, 0x054b, "DataFieldCustomValue8" }, + { 0x20, 0x054c, "DataFieldCustomValue9" }, + { 0x20, 0x054d, "DataFieldCustomValue10" }, + { 0x20, 0x054e, "DataFieldCustomValue11" }, + { 0x20, 0x054f, "DataFieldCustomValue12" }, + { 0x20, 0x0550, "DataFieldCustomValue13" }, + { 0x20, 0x0551, "DataFieldCustomValue14" }, + { 0x20, 0x0552, "DataFieldCustomValue15" }, + { 0x20, 0x0553, "DataFieldCustomValue16" }, + { 0x20, 0x0554, "DataFieldCustomValue17" }, + { 0x20, 0x0555, "DataFieldCustomValue18" }, + { 0x20, 0x0556, "DataFieldCustomValue19" }, + { 0x20, 0x0557, "DataFieldCustomValue20" }, + { 0x20, 0x0558, "DataFieldCustomValue21" }, + { 0x20, 0x0559, "DataFieldCustomValue22" }, + { 0x20, 0x055a, "DataFieldCustomValue23" }, + { 0x20, 0x055b, "DataFieldCustomValue24" }, + { 0x20, 0x055c, "DataFieldCustomValue25" }, + { 0x20, 0x055d, "DataFieldCustomValue26" }, + { 0x20, 0x055e, "DataFieldCustomValue27" }, + { 0x20, 0x055f, "DataFieldCustomValue28" }, + { 0x20, 0x0560, "DataFieldGeneric" }, + { 0x20, 0x0561, "DataFieldGenericGUIDorPROPERTYKEY" }, + { 0x20, 0x0562, "DataFieldGenericCategoryGUID" }, + { 0x20, 0x0563, "DataFieldGenericTypeGUID" }, + { 0x20, 0x0564, "DataFieldGenericEventPROPERTYKEY" }, + { 0x20, 0x0565, "DataFieldGenericPropertyPROPERTYKEY" }, + { 0x20, 0x0566, "DataFieldGenericDataFieldPROPERTYKEY" }, + { 0x20, 0x0567, "DataFieldGenericEvent" }, + { 0x20, 0x0568, "DataFieldGenericProperty" }, + { 0x20, 0x0569, "DataFieldGenericDataField" }, + { 0x20, 0x056a, "DataFieldEnumeratorTableRowIndex" }, + { 0x20, 0x056b, "DataFieldEnumeratorTableRowCount" }, + { 0x20, 0x056c, "DataFieldGenericGUIDorPROPERTYKEYkind" }, + { 0x20, 0x056d, "DataFieldGenericGUID" }, + { 0x20, 0x056e, "DataFieldGenericPROPERTYKEY" }, + { 0x20, 0x056f, "DataFieldGenericTopLevelCollectionID" }, + { 0x20, 0x0570, "DataFieldGenericReportID" }, + { 0x20, 0x0571, "DataFieldGenericReportItemPositionIndex" }, + { 0x20, 0x0572, "DataFieldGenericFirmwareVARTYPE" }, + { 0x20, 0x0573, "DataFieldGenericUnitofMeasure" }, + { 0x20, 0x0574, "DataFieldGenericUnitExponent" }, + { 0x20, 0x0575, "DataFieldGenericReportSize" }, + { 0x20, 0x0576, "DataFieldGenericReportCount" }, + { 0x20, 0x0580, "PropertyGeneric" }, + { 0x20, 0x0581, "PropertyEnumeratorTableRowIndex" }, + { 0x20, 0x0582, "PropertyEnumeratorTableRowCount" }, + { 0x20, 0x0590, "DataFieldPersonalActivity" }, + { 0x20, 0x0591, "DataFieldActivityType" }, + { 0x20, 0x0592, "DataFieldActivityState" }, + { 0x20, 0x0593, "DataFieldDevicePosition" }, + { 0x20, 0x0594, "DataFieldStepCount" }, + { 0x20, 0x0595, "DataFieldStepCountReset" }, + { 0x20, 0x0596, "DataFieldStepDuration" }, + { 0x20, 0x0597, "DataFieldStepType" }, + { 0x20, 0x05a0, "PropertyMinimumActivityDetectionInterval" }, + { 0x20, 0x05a1, "PropertySupportedActivityTypes" }, + { 0x20, 0x05a2, "PropertySubscribedActivityTypes" }, + { 0x20, 0x05a3, "PropertySupportedStepTypes" }, + { 0x20, 0x05a4, "PropertySubscribedStepTypes" }, + { 0x20, 0x05a5, "PropertyFloorHeight" }, + { 0x20, 0x05b0, "DataFieldCustomTypeID" }, + { 0x20, 0x05c0, "PropertyCustom" }, + { 0x20, 0x05c1, "PropertyCustomValue1" }, + { 0x20, 0x05c2, "PropertyCustomValue2" }, + { 0x20, 0x05c3, "PropertyCustomValue3" }, + { 0x20, 0x05c4, "PropertyCustomValue4" }, + { 0x20, 0x05c5, "PropertyCustomValue5" }, + { 0x20, 0x05c6, "PropertyCustomValue6" }, + { 0x20, 0x05c7, "PropertyCustomValue7" }, + { 0x20, 0x05c8, "PropertyCustomValue8" }, + { 0x20, 0x05c9, "PropertyCustomValue9" }, + { 0x20, 0x05ca, "PropertyCustomValue10" }, + { 0x20, 0x05cb, "PropertyCustomValue11" }, + { 0x20, 0x05cc, "PropertyCustomValue12" }, + { 0x20, 0x05cd, "PropertyCustomValue13" }, + { 0x20, 0x05ce, "PropertyCustomValue14" }, + { 0x20, 0x05cf, "PropertyCustomValue15" }, + { 0x20, 0x05d0, "PropertyCustomValue16" }, + { 0x20, 0x05e0, "DataFieldHinge" }, + { 0x20, 0x05e1, "DataFieldHingeAngle" }, + { 0x20, 0x05f0, "DataFieldGestureSensor" }, + { 0x20, 0x05f1, "DataFieldGestureState" }, + { 0x20, 0x05f2, "DataFieldHingeFoldInitialAngle" }, + { 0x20, 0x05f3, "DataFieldHingeFoldFinalAngle" }, + { 0x20, 0x05f4, "DataFieldHingeFoldContributingPanel" }, + { 0x20, 0x05f5, "DataFieldHingeFoldType" }, + { 0x20, 0x0800, "SensorStateUndefined" }, + { 0x20, 0x0801, "SensorStateReady" }, + { 0x20, 0x0802, "SensorStateNotAvailable" }, + { 0x20, 0x0803, "SensorStateNoData" }, + { 0x20, 0x0804, "SensorStateInitializing" }, + { 0x20, 0x0805, "SensorStateAccessDenied" }, + { 0x20, 0x0806, "SensorStateError" }, + { 0x20, 0x0810, "SensorEventUnknown" }, + { 0x20, 0x0811, "SensorEventStateChanged" }, + { 0x20, 0x0812, "SensorEventPropertyChanged" }, + { 0x20, 0x0813, "SensorEventDataUpdated" }, + { 0x20, 0x0814, "SensorEventPollResponse" }, + { 0x20, 0x0815, "SensorEventChangeSensitivity" }, + { 0x20, 0x0816, "SensorEventRangeMaximumReached" }, + { 0x20, 0x0817, "SensorEventRangeMinimumReached" }, + { 0x20, 0x0818, "SensorEventHighThresholdCrossUpward" }, + { 0x20, 0x0819, "SensorEventHighThresholdCrossDownward" }, + { 0x20, 0x081a, "SensorEventLowThresholdCrossUpward" }, + { 0x20, 0x081b, "SensorEventLowThresholdCrossDownward" }, + { 0x20, 0x081c, "SensorEventZeroThresholdCrossUpward" }, + { 0x20, 0x081d, "SensorEventZeroThresholdCrossDownward" }, + { 0x20, 0x081e, "SensorEventPeriodExceeded" }, + { 0x20, 0x081f, "SensorEventFrequencyExceeded" }, + { 0x20, 0x0820, "SensorEventComplexTrigger" }, + { 0x20, 0x0830, "ConnectionTypePCIntegrated" }, + { 0x20, 0x0831, "ConnectionTypePCAttached" }, + { 0x20, 0x0832, "ConnectionTypePCExternal" }, + { 0x20, 0x0840, "ReportingStateReportNoEvents" }, + { 0x20, 0x0841, "ReportingStateReportAllEvents" }, + { 0x20, 0x0842, "ReportingStateReportThresholdEvents" }, + { 0x20, 0x0843, "ReportingStateWakeOnNoEvents" }, + { 0x20, 0x0844, "ReportingStateWakeOnAllEvents" }, + { 0x20, 0x0845, "ReportingStateWakeOnThresholdEvents" }, + { 0x20, 0x0846, "ReportingStateAnytime" }, + { 0x20, 0x0850, "PowerStateUndefined" }, + { 0x20, 0x0851, "PowerStateD0FullPower" }, + { 0x20, 0x0852, "PowerStateD1LowPower" }, + { 0x20, 0x0853, "PowerStateD2StandbyPowerwithWakeup" }, + { 0x20, 0x0854, "PowerStateD3SleepwithWakeup" }, + { 0x20, 0x0855, "PowerStateD4PowerOff" }, + { 0x20, 0x0860, "AccuracyDefault" }, + { 0x20, 0x0861, "AccuracyHigh" }, + { 0x20, 0x0862, "AccuracyMedium" }, + { 0x20, 0x0863, "AccuracyLow" }, + { 0x20, 0x0870, "FixQualityNoFix" }, + { 0x20, 0x0871, "FixQualityGPS" }, + { 0x20, 0x0872, "FixQualityDGPS" }, + { 0x20, 0x0880, "FixTypeNoFix" }, + { 0x20, 0x0881, "FixTypeGPSSPSModeFixValid" }, + { 0x20, 0x0882, "FixTypeDGPSSPSModeFixValid" }, + { 0x20, 0x0883, "FixTypeGPSPPSModeFixValid" }, + { 0x20, 0x0884, "FixTypeRealTimeKinematic" }, + { 0x20, 0x0885, "FixTypeFloatRTK" }, + { 0x20, 0x0886, "FixTypeEstimateddeadreckoned" }, + { 0x20, 0x0887, "FixTypeManualInputMode" }, + { 0x20, 0x0888, "FixTypeSimulatorMode" }, + { 0x20, 0x0890, "GPSOperationModeManual" }, + { 0x20, 0x0891, "GPSOperationModeAutomatic" }, + { 0x20, 0x08a0, "GPSSelectionModeAutonomous" }, + { 0x20, 0x08a1, "GPSSelectionModeDGPS" }, + { 0x20, 0x08a2, "GPSSelectionModeEstimateddeadreckoned" }, + { 0x20, 0x08a3, "GPSSelectionModeManualInput" }, + { 0x20, 0x08a4, "GPSSelectionModeSimulator" }, + { 0x20, 0x08a5, "GPSSelectionModeDataNotValid" }, + { 0x20, 0x08b0, "GPSStatusDataValid" }, + { 0x20, 0x08b1, "GPSStatusDataNotValid" }, + { 0x20, 0x08c0, "DayofWeekSunday" }, + { 0x20, 0x08c1, "DayofWeekMonday" }, + { 0x20, 0x08c2, "DayofWeekTuesday" }, + { 0x20, 0x08c3, "DayofWeekWednesday" }, + { 0x20, 0x08c4, "DayofWeekThursday" }, + { 0x20, 0x08c5, "DayofWeekFriday" }, + { 0x20, 0x08c6, "DayofWeekSaturday" }, + { 0x20, 0x08d0, "KindCategory" }, + { 0x20, 0x08d1, "KindType" }, + { 0x20, 0x08d2, "KindEvent" }, + { 0x20, 0x08d3, "KindProperty" }, + { 0x20, 0x08d4, "KindDataField" }, + { 0x20, 0x08e0, "MagnetometerAccuracyLow" }, + { 0x20, 0x08e1, "MagnetometerAccuracyMedium" }, + { 0x20, 0x08e2, "MagnetometerAccuracyHigh" }, + { 0x20, 0x08f0, "SimpleOrientationDirectionNotRotated" }, + { 0x20, 0x08f1, "SimpleOrientationDirectionRotated90DegreesCCW" }, + { 0x20, 0x08f2, "SimpleOrientationDirectionRotated180DegreesCCW" }, + { 0x20, 0x08f3, "SimpleOrientationDirectionRotated270DegreesCCW" }, + { 0x20, 0x08f4, "SimpleOrientationDirectionFaceUp" }, + { 0x20, 0x08f5, "SimpleOrientationDirectionFaceDown" }, + { 0x20, 0x0900, "VT_NULL" }, + { 0x20, 0x0901, "VT_BOOL" }, + { 0x20, 0x0902, "VT_UI1" }, + { 0x20, 0x0903, "VT_I1" }, + { 0x20, 0x0904, "VT_UI2" }, + { 0x20, 0x0905, "VT_I2" }, + { 0x20, 0x0906, "VT_UI4" }, + { 0x20, 0x0907, "VT_I4" }, + { 0x20, 0x0908, "VT_UI8" }, + { 0x20, 0x0909, "VT_I8" }, + { 0x20, 0x090a, "VT_R4" }, + { 0x20, 0x090b, "VT_R8" }, + { 0x20, 0x090c, "VT_WSTR" }, + { 0x20, 0x090d, "VT_STR" }, + { 0x20, 0x090e, "VT_CLSID" }, + { 0x20, 0x090f, "VT_VECTORVT_UI1" }, + { 0x20, 0x0910, "VT_F16E0" }, + { 0x20, 0x0911, "VT_F16E1" }, + { 0x20, 0x0912, "VT_F16E2" }, + { 0x20, 0x0913, "VT_F16E3" }, + { 0x20, 0x0914, "VT_F16E4" }, + { 0x20, 0x0915, "VT_F16E5" }, + { 0x20, 0x0916, "VT_F16E6" }, + { 0x20, 0x0917, "VT_F16E7" }, + { 0x20, 0x0918, "VT_F16E8" }, + { 0x20, 0x0919, "VT_F16E9" }, + { 0x20, 0x091a, "VT_F16EA" }, + { 0x20, 0x091b, "VT_F16EB" }, + { 0x20, 0x091c, "VT_F16EC" }, + { 0x20, 0x091d, "VT_F16ED" }, + { 0x20, 0x091e, "VT_F16EE" }, + { 0x20, 0x091f, "VT_F16EF" }, + { 0x20, 0x0920, "VT_F32E0" }, + { 0x20, 0x0921, "VT_F32E1" }, + { 0x20, 0x0922, "VT_F32E2" }, + { 0x20, 0x0923, "VT_F32E3" }, + { 0x20, 0x0924, "VT_F32E4" }, + { 0x20, 0x0925, "VT_F32E5" }, + { 0x20, 0x0926, "VT_F32E6" }, + { 0x20, 0x0927, "VT_F32E7" }, + { 0x20, 0x0928, "VT_F32E8" }, + { 0x20, 0x0929, "VT_F32E9" }, + { 0x20, 0x092a, "VT_F32EA" }, + { 0x20, 0x092b, "VT_F32EB" }, + { 0x20, 0x092c, "VT_F32EC" }, + { 0x20, 0x092d, "VT_F32ED" }, + { 0x20, 0x092e, "VT_F32EE" }, + { 0x20, 0x092f, "VT_F32EF" }, + { 0x20, 0x0930, "ActivityTypeUnknown" }, + { 0x20, 0x0931, "ActivityTypeStationary" }, + { 0x20, 0x0932, "ActivityTypeFidgeting" }, + { 0x20, 0x0933, "ActivityTypeWalking" }, + { 0x20, 0x0934, "ActivityTypeRunning" }, + { 0x20, 0x0935, "ActivityTypeInVehicle" }, + { 0x20, 0x0936, "ActivityTypeBiking" }, + { 0x20, 0x0937, "ActivityTypeIdle" }, + { 0x20, 0x0940, "UnitNotSpecified" }, + { 0x20, 0x0941, "UnitLux" }, + { 0x20, 0x0942, "UnitDegreesKelvin" }, + { 0x20, 0x0943, "UnitDegreesCelsius" }, + { 0x20, 0x0944, "UnitPascal" }, + { 0x20, 0x0945, "UnitNewton" }, + { 0x20, 0x0946, "UnitMetersSecond" }, + { 0x20, 0x0947, "UnitKilogram" }, + { 0x20, 0x0948, "UnitMeter" }, + { 0x20, 0x0949, "UnitMetersSecondSecond" }, + { 0x20, 0x094a, "UnitFarad" }, + { 0x20, 0x094b, "UnitAmpere" }, + { 0x20, 0x094c, "UnitWatt" }, + { 0x20, 0x094d, "UnitHenry" }, + { 0x20, 0x094e, "UnitOhm" }, + { 0x20, 0x094f, "UnitVolt" }, + { 0x20, 0x0950, "UnitHertz" }, + { 0x20, 0x0951, "UnitBar" }, + { 0x20, 0x0952, "UnitDegreesAnticlockwise" }, + { 0x20, 0x0953, "UnitDegreesClockwise" }, + { 0x20, 0x0954, "UnitDegrees" }, + { 0x20, 0x0955, "UnitDegreesSecond" }, + { 0x20, 0x0956, "UnitDegreesSecondSecond" }, + { 0x20, 0x0957, "UnitKnot" }, + { 0x20, 0x0958, "UnitPercent" }, + { 0x20, 0x0959, "UnitSecond" }, + { 0x20, 0x095a, "UnitMillisecond" }, + { 0x20, 0x095b, "UnitG" }, + { 0x20, 0x095c, "UnitBytes" }, + { 0x20, 0x095d, "UnitMilligauss" }, + { 0x20, 0x095e, "UnitBits" }, + { 0x20, 0x0960, "ActivityStateNoStateChange" }, + { 0x20, 0x0961, "ActivityStateStartActivity" }, + { 0x20, 0x0962, "ActivityStateEndActivity" }, + { 0x20, 0x0970, "Exponent0" }, + { 0x20, 0x0971, "Exponent1" }, + { 0x20, 0x0972, "Exponent2" }, + { 0x20, 0x0973, "Exponent3" }, + { 0x20, 0x0974, "Exponent4" }, + { 0x20, 0x0975, "Exponent5" }, + { 0x20, 0x0976, "Exponent6" }, + { 0x20, 0x0977, "Exponent7" }, + { 0x20, 0x0978, "Exponent8" }, + { 0x20, 0x0979, "Exponent9" }, + { 0x20, 0x097a, "ExponentA" }, + { 0x20, 0x097b, "ExponentB" }, + { 0x20, 0x097c, "ExponentC" }, + { 0x20, 0x097d, "ExponentD" }, + { 0x20, 0x097e, "ExponentE" }, + { 0x20, 0x097f, "ExponentF" }, + { 0x20, 0x0980, "DevicePositionUnknown" }, + { 0x20, 0x0981, "DevicePositionUnchanged" }, + { 0x20, 0x0982, "DevicePositionOnDesk" }, + { 0x20, 0x0983, "DevicePositionInHand" }, + { 0x20, 0x0984, "DevicePositionMovinginBag" }, + { 0x20, 0x0985, "DevicePositionStationaryinBag" }, + { 0x20, 0x0990, "StepTypeUnknown" }, + { 0x20, 0x0991, "StepTypeWalking" }, + { 0x20, 0x0992, "StepTypeRunning" }, + { 0x20, 0x09a0, "GestureStateUnknown" }, + { 0x20, 0x09a1, "GestureStateStarted" }, + { 0x20, 0x09a2, "GestureStateCompleted" }, + { 0x20, 0x09a3, "GestureStateCancelled" }, + { 0x20, 0x09b0, "HingeFoldContributingPanelUnknown" }, + { 0x20, 0x09b1, "HingeFoldContributingPanelPanel1" }, + { 0x20, 0x09b2, "HingeFoldContributingPanelPanel2" }, + { 0x20, 0x09b3, "HingeFoldContributingPanelBoth" }, + { 0x20, 0x09b4, "HingeFoldTypeUnknown" }, + { 0x20, 0x09b5, "HingeFoldTypeIncreasing" }, + { 0x20, 0x09b6, "HingeFoldTypeDecreasing" }, + { 0x20, 0x09c0, "HumanPresenceDetectionTypeVendorDefinedNonBiometric" }, + { 0x20, 0x09c1, "HumanPresenceDetectionTypeVendorDefinedBiometric" }, + { 0x20, 0x09c2, "HumanPresenceDetectionTypeFacialBiometric" }, + { 0x20, 0x09c3, "HumanPresenceDetectionTypeAudioBiometric" }, + { 0x20, 0x1000, "ModifierChangeSensitivityAbsolute" }, + { 0x20, 0x2000, "ModifierMaximum" }, + { 0x20, 0x3000, "ModifierMinimum" }, + { 0x20, 0x4000, "ModifierAccuracy" }, + { 0x20, 0x5000, "ModifierResolution" }, + { 0x20, 0x6000, "ModifierThresholdHigh" }, + { 0x20, 0x7000, "ModifierThresholdLow" }, + { 0x20, 0x8000, "ModifierCalibrationOffset" }, + { 0x20, 0x9000, "ModifierCalibrationMultiplier" }, + { 0x20, 0xa000, "ModifierReportInterval" }, + { 0x20, 0xb000, "ModifierFrequencyMax" }, + { 0x20, 0xc000, "ModifierPeriodMax" }, + { 0x20, 0xd000, "ModifierChangeSensitivityPercentofRange" }, + { 0x20, 0xe000, "ModifierChangeSensitivityPercentRelative" }, + { 0x20, 0xf000, "ModifierVendorReserved" }, + { 0x40, 0, "MedicalInstrument" }, + { 0x40, 0x0001, "MedicalUltrasound" }, + { 0x40, 0x0020, "VCRAcquisition" }, + { 0x40, 0x0021, "FreezeThaw" }, + { 0x40, 0x0022, "ClipStore" }, + { 0x40, 0x0023, "Update" }, + { 0x40, 0x0024, "Next" }, + { 0x40, 0x0025, "Save" }, + { 0x40, 0x0026, "Print" }, + { 0x40, 0x0027, "MicrophoneEnable" }, + { 0x40, 0x0040, "Cine" }, + { 0x40, 0x0041, "TransmitPower" }, + { 0x40, 0x0042, "Volume" }, + { 0x40, 0x0043, "Focus" }, + { 0x40, 0x0044, "Depth" }, + { 0x40, 0x0060, "SoftStepPrimary" }, + { 0x40, 0x0061, "SoftStepSecondary" }, + { 0x40, 0x0070, "DepthGainCompensation" }, + { 0x40, 0x0080, "ZoomSelect" }, + { 0x40, 0x0081, "ZoomAdjust" }, + { 0x40, 0x0082, "SpectralDopplerModeSelect" }, + { 0x40, 0x0083, "SpectralDopplerAdjust" }, + { 0x40, 0x0084, "ColorDopplerModeSelect" }, + { 0x40, 0x0085, "ColorDopplerAdjust" }, + { 0x40, 0x0086, "MotionModeSelect" }, + { 0x40, 0x0087, "MotionModeAdjust" }, + { 0x40, 0x0088, "2DModeSelect" }, + { 0x40, 0x0089, "2DModeAdjust" }, + { 0x40, 0x00a0, "SoftControlSelect" }, + { 0x40, 0x00a1, "SoftControlAdjust" }, + { 0x41, 0, "BrailleDisplay" }, + { 0x41, 0x0001, "BrailleDisplay" }, + { 0x41, 0x0002, "BrailleRow" }, + { 0x41, 0x0003, "8DotBrailleCell" }, + { 0x41, 0x0004, "6DotBrailleCell" }, + { 0x41, 0x0005, "NumberofBrailleCells" }, + { 0x41, 0x0006, "ScreenReaderControl" }, + { 0x41, 0x0007, "ScreenReaderIdentifier" }, + { 0x41, 0x00fa, "RouterSet1" }, + { 0x41, 0x00fb, "RouterSet2" }, + { 0x41, 0x00fc, "RouterSet3" }, + { 0x41, 0x0100, "RouterKey" }, + { 0x41, 0x0101, "RowRouterKey" }, + { 0x41, 0x0200, "BrailleButtons" }, + { 0x41, 0x0201, "BrailleKeyboardDot1" }, + { 0x41, 0x0202, "BrailleKeyboardDot2" }, + { 0x41, 0x0203, "BrailleKeyboardDot3" }, + { 0x41, 0x0204, "BrailleKeyboardDot4" }, + { 0x41, 0x0205, "BrailleKeyboardDot5" }, + { 0x41, 0x0206, "BrailleKeyboardDot6" }, + { 0x41, 0x0207, "BrailleKeyboardDot7" }, + { 0x41, 0x0208, "BrailleKeyboardDot8" }, + { 0x41, 0x0209, "BrailleKeyboardSpace" }, + { 0x41, 0x020a, "BrailleKeyboardLeftSpace" }, + { 0x41, 0x020b, "BrailleKeyboardRightSpace" }, + { 0x41, 0x020c, "BrailleFaceControls" }, + { 0x41, 0x020d, "BrailleLeftControls" }, + { 0x41, 0x020e, "BrailleRightControls" }, + { 0x41, 0x020f, "BrailleTopControls" }, + { 0x41, 0x0210, "BrailleJoystickCenter" }, + { 0x41, 0x0211, "BrailleJoystickUp" }, + { 0x41, 0x0212, "BrailleJoystickDown" }, + { 0x41, 0x0213, "BrailleJoystickLeft" }, + { 0x41, 0x0214, "BrailleJoystickRight" }, + { 0x41, 0x0215, "BrailleDPadCenter" }, + { 0x41, 0x0216, "BrailleDPadUp" }, + { 0x41, 0x0217, "BrailleDPadDown" }, + { 0x41, 0x0218, "BrailleDPadLeft" }, + { 0x41, 0x0219, "BrailleDPadRight" }, + { 0x41, 0x021a, "BraillePanLeft" }, + { 0x41, 0x021b, "BraillePanRight" }, + { 0x41, 0x021c, "BrailleRockerUp" }, + { 0x41, 0x021d, "BrailleRockerDown" }, + { 0x41, 0x021e, "BrailleRockerPress" }, + { 0x59, 0, "LightingAndIllumination" }, + { 0x59, 0x0001, "LampArray" }, + { 0x59, 0x0002, "LampArrayAttributesReport" }, + { 0x59, 0x0003, "LampCount" }, + { 0x59, 0x0004, "BoundingBoxWidthInMicrometers" }, + { 0x59, 0x0005, "BoundingBoxHeightInMicrometers" }, + { 0x59, 0x0006, "BoundingBoxDepthInMicrometers" }, + { 0x59, 0x0007, "LampArrayKind" }, + { 0x59, 0x0008, "MinUpdateIntervalInMicroseconds" }, + { 0x59, 0x0020, "LampAttributesRequestReport" }, + { 0x59, 0x0021, "LampId" }, + { 0x59, 0x0022, "LampAttributesResponseReport" }, + { 0x59, 0x0023, "PositionXInMicrometers" }, + { 0x59, 0x0024, "PositionYInMicrometers" }, + { 0x59, 0x0025, "PositionZInMicrometers" }, + { 0x59, 0x0026, "LampPurposes" }, + { 0x59, 0x0027, "UpdateLatencyInMicroseconds" }, + { 0x59, 0x0028, "RedLevelCount" }, + { 0x59, 0x0029, "GreenLevelCount" }, + { 0x59, 0x002a, "BlueLevelCount" }, + { 0x59, 0x002b, "IntensityLevelCount" }, + { 0x59, 0x002c, "IsProgrammable" }, + { 0x59, 0x002d, "InputBinding" }, + { 0x59, 0x0050, "LampMultiUpdateReport" }, + { 0x59, 0x0051, "RedUpdateChannel" }, + { 0x59, 0x0052, "GreenUpdateChannel" }, + { 0x59, 0x0053, "BlueUpdateChannel" }, + { 0x59, 0x0054, "IntensityUpdateChannel" }, + { 0x59, 0x0055, "LampUpdateFlags" }, + { 0x59, 0x0060, "LampRangeUpdateReport" }, + { 0x59, 0x0061, "LampIdStart" }, + { 0x59, 0x0062, "LampIdEnd" }, + { 0x59, 0x0070, "LampArrayControlReport" }, + { 0x59, 0x0071, "AutonomousMode" }, + { 0x80, 0, "Monitor" }, + { 0x80, 0x0001, "MonitorControl" }, + { 0x80, 0x0002, "EDIDInformation" }, + { 0x80, 0x0003, "VDIFInformation" }, + { 0x80, 0x0004, "VESAVersion" }, + { 0x81, 0, "MonitorEnumerated" }, + { 0x82, 0, "VESAVirtualControls" }, + { 0x82, 0x0001, "Degauss" }, + { 0x82, 0x0010, "Brightness" }, + { 0x82, 0x0012, "Contrast" }, + { 0x82, 0x0016, "RedVideoGain" }, + { 0x82, 0x0018, "GreenVideoGain" }, + { 0x82, 0x001a, "BlueVideoGain" }, + { 0x82, 0x001c, "Focus" }, + { 0x82, 0x0020, "HorizontalPosition" }, + { 0x82, 0x0022, "HorizontalSize" }, + { 0x82, 0x0024, "HorizontalPincushion" }, + { 0x82, 0x0026, "HorizontalPincushionBalance" }, + { 0x82, 0x0028, "HorizontalMisconvergence" }, + { 0x82, 0x002a, "HorizontalLinearity" }, + { 0x82, 0x002c, "HorizontalLinearityBalance" }, + { 0x82, 0x0030, "VerticalPosition" }, + { 0x82, 0x0032, "VerticalSize" }, + { 0x82, 0x0034, "VerticalPincushion" }, + { 0x82, 0x0036, "VerticalPincushionBalance" }, + { 0x82, 0x0038, "VerticalMisconvergence" }, + { 0x82, 0x003a, "VerticalLinearity" }, + { 0x82, 0x003c, "VerticalLinearityBalance" }, + { 0x82, 0x0040, "ParallelogramDistortionKeyBalance" }, + { 0x82, 0x0042, "TrapezoidalDistortionKey" }, + { 0x82, 0x0044, "TiltRotation" }, + { 0x82, 0x0046, "TopCornerDistortionControl" }, + { 0x82, 0x0048, "TopCornerDistortionBalance" }, + { 0x82, 0x004a, "BottomCornerDistortionControl" }, + { 0x82, 0x004c, "BottomCornerDistortionBalance" }, + { 0x82, 0x0056, "HorizontalMoir" }, + { 0x82, 0x0058, "VerticalMoir" }, + { 0x82, 0x005e, "InputLevelSelect" }, + { 0x82, 0x0060, "InputSourceSelect" }, + { 0x82, 0x006c, "RedVideoBlackLevel" }, + { 0x82, 0x006e, "GreenVideoBlackLevel" }, + { 0x82, 0x0070, "BlueVideoBlackLevel" }, + { 0x82, 0x00a2, "AutoSizeCenter" }, + { 0x82, 0x00a4, "PolarityHorizontalSynchronization" }, + { 0x82, 0x00a6, "PolarityVerticalSynchronization" }, + { 0x82, 0x00a8, "SynchronizationType" }, + { 0x82, 0x00aa, "ScreenOrientation" }, + { 0x82, 0x00ac, "HorizontalFrequency" }, + { 0x82, 0x00ae, "VerticalFrequency" }, + { 0x82, 0x00b0, "Settings" }, + { 0x82, 0x00ca, "OnScreenDisplay" }, + { 0x82, 0x00d4, "StereoMode" }, + { 0x84, 0, "Power" }, + { 0x84, 0x0001, "iName" }, + { 0x84, 0x0002, "PresentStatus" }, + { 0x84, 0x0003, "ChangedStatus" }, + { 0x84, 0x0004, "UPS" }, + { 0x84, 0x0005, "PowerSupply" }, + { 0x84, 0x0010, "BatterySystem" }, + { 0x84, 0x0011, "BatterySystemId" }, + { 0x84, 0x0012, "Battery" }, + { 0x84, 0x0013, "BatteryId" }, + { 0x84, 0x0014, "Charger" }, + { 0x84, 0x0015, "ChargerId" }, + { 0x84, 0x0016, "PowerConverter" }, + { 0x84, 0x0017, "PowerConverterId" }, + { 0x84, 0x0018, "OutletSystem" }, + { 0x84, 0x0019, "OutletSystemId" }, + { 0x84, 0x001a, "Input" }, + { 0x84, 0x001b, "InputId" }, + { 0x84, 0x001c, "Output" }, + { 0x84, 0x001d, "OutputId" }, + { 0x84, 0x001e, "Flow" }, + { 0x84, 0x001f, "FlowId" }, + { 0x84, 0x0020, "Outlet" }, + { 0x84, 0x0021, "OutletId" }, + { 0x84, 0x0022, "Gang" }, + { 0x84, 0x0023, "GangId" }, + { 0x84, 0x0024, "PowerSummary" }, + { 0x84, 0x0025, "PowerSummaryId" }, + { 0x84, 0x0030, "Voltage" }, + { 0x84, 0x0031, "Current" }, + { 0x84, 0x0032, "Frequency" }, + { 0x84, 0x0033, "ApparentPower" }, + { 0x84, 0x0034, "ActivePower" }, + { 0x84, 0x0035, "PercentLoad" }, + { 0x84, 0x0036, "Temperature" }, + { 0x84, 0x0037, "Humidity" }, + { 0x84, 0x0038, "BadCount" }, + { 0x84, 0x0040, "ConfigVoltage" }, + { 0x84, 0x0041, "ConfigCurrent" }, + { 0x84, 0x0042, "ConfigFrequency" }, + { 0x84, 0x0043, "ConfigApparentPower" }, + { 0x84, 0x0044, "ConfigActivePower" }, + { 0x84, 0x0045, "ConfigPercentLoad" }, + { 0x84, 0x0046, "ConfigTemperature" }, + { 0x84, 0x0047, "ConfigHumidity" }, + { 0x84, 0x0050, "SwitchOnControl" }, + { 0x84, 0x0051, "SwitchOffControl" }, + { 0x84, 0x0052, "ToggleControl" }, + { 0x84, 0x0053, "LowVoltageTransfer" }, + { 0x84, 0x0054, "HighVoltageTransfer" }, + { 0x84, 0x0055, "DelayBeforeReboot" }, + { 0x84, 0x0056, "DelayBeforeStartup" }, + { 0x84, 0x0057, "DelayBeforeShutdown" }, + { 0x84, 0x0058, "Test" }, + { 0x84, 0x0059, "ModuleReset" }, + { 0x84, 0x005a, "AudibleAlarmControl" }, + { 0x84, 0x0060, "Present" }, + { 0x84, 0x0061, "Good" }, + { 0x84, 0x0062, "InternalFailure" }, + { 0x84, 0x0063, "VoltagOutOfRange" }, + { 0x84, 0x0064, "FrequencyOutOfRange" }, + { 0x84, 0x0065, "Overload" }, + { 0x84, 0x0066, "OverCharged" }, + { 0x84, 0x0067, "OverTemperature" }, + { 0x84, 0x0068, "ShutdownRequested" }, + { 0x84, 0x0069, "ShutdownImminent" }, + { 0x84, 0x006b, "SwitchOnOff" }, + { 0x84, 0x006c, "Switchable" }, + { 0x84, 0x006d, "Used" }, + { 0x84, 0x006e, "Boost" }, + { 0x84, 0x006f, "Buck" }, + { 0x84, 0x0070, "Initialized" }, + { 0x84, 0x0071, "Tested" }, + { 0x84, 0x0072, "AwaitingPower" }, + { 0x84, 0x0073, "CommunicationLost" }, + { 0x84, 0x00fd, "iManufacturer" }, + { 0x84, 0x00fe, "iProduct" }, + { 0x84, 0x00ff, "iSerialNumber" }, + { 0x85, 0, "BatterySystem" }, + { 0x85, 0x0001, "SmartBatteryBatteryMode" }, + { 0x85, 0x0002, "SmartBatteryBatteryStatus" }, + { 0x85, 0x0003, "SmartBatteryAlarmWarning" }, + { 0x85, 0x0004, "SmartBatteryChargerMode" }, + { 0x85, 0x0005, "SmartBatteryChargerStatus" }, + { 0x85, 0x0006, "SmartBatteryChargerSpecInfo" }, + { 0x85, 0x0007, "SmartBatterySelectorState" }, + { 0x85, 0x0008, "SmartBatterySelectorPresets" }, + { 0x85, 0x0009, "SmartBatterySelectorInfo" }, + { 0x85, 0x0010, "OptionalMfgFunction1" }, + { 0x85, 0x0011, "OptionalMfgFunction2" }, + { 0x85, 0x0012, "OptionalMfgFunction3" }, + { 0x85, 0x0013, "OptionalMfgFunction4" }, + { 0x85, 0x0014, "OptionalMfgFunction5" }, + { 0x85, 0x0015, "ConnectionToSMBus" }, + { 0x85, 0x0016, "OutputConnection" }, + { 0x85, 0x0017, "ChargerConnection" }, + { 0x85, 0x0018, "BatteryInsertion" }, + { 0x85, 0x0019, "UseNext" }, + { 0x85, 0x001a, "OKToUse" }, + { 0x85, 0x001b, "BatterySupported" }, + { 0x85, 0x001c, "SelectorRevision" }, + { 0x85, 0x001d, "ChargingIndicator" }, + { 0x85, 0x0028, "ManufacturerAccess" }, + { 0x85, 0x0029, "RemainingCapacityLimit" }, + { 0x85, 0x002a, "RemainingTimeLimit" }, + { 0x85, 0x002b, "AtRate" }, + { 0x85, 0x002c, "CapacityMode" }, + { 0x85, 0x002d, "BroadcastToCharger" }, + { 0x85, 0x002e, "PrimaryBattery" }, + { 0x85, 0x002f, "ChargeController" }, + { 0x85, 0x0040, "TerminateCharge" }, + { 0x85, 0x0041, "TerminateDischarge" }, + { 0x85, 0x0042, "BelowRemainingCapacityLimit" }, + { 0x85, 0x0043, "RemainingTimeLimitExpired" }, + { 0x85, 0x0044, "Charging" }, + { 0x85, 0x0045, "Discharging" }, + { 0x85, 0x0046, "FullyCharged" }, + { 0x85, 0x0047, "FullyDischarged" }, + { 0x85, 0x0048, "ConditioningFlag" }, + { 0x85, 0x0049, "AtRateOK" }, + { 0x85, 0x004a, "SmartBatteryErrorCode" }, + { 0x85, 0x004b, "NeedReplacement" }, + { 0x85, 0x0060, "AtRateTimeToFull" }, + { 0x85, 0x0061, "AtRateTimeToEmpty" }, + { 0x85, 0x0062, "AverageCurrent" }, + { 0x85, 0x0063, "MaxError" }, + { 0x85, 0x0064, "RelativeStateOfCharge" }, + { 0x85, 0x0065, "AbsoluteStateOfCharge" }, + { 0x85, 0x0066, "RemainingCapacity" }, + { 0x85, 0x0067, "FullChargeCapacity" }, + { 0x85, 0x0068, "RunTimeToEmpty" }, + { 0x85, 0x0069, "AverageTimeToEmpty" }, + { 0x85, 0x006a, "AverageTimeToFull" }, + { 0x85, 0x006b, "CycleCount" }, + { 0x85, 0x0080, "BatteryPackModelLevel" }, + { 0x85, 0x0081, "InternalChargeController" }, + { 0x85, 0x0082, "PrimaryBatterySupport" }, + { 0x85, 0x0083, "DesignCapacity" }, + { 0x85, 0x0084, "SpecificationInfo" }, + { 0x85, 0x0085, "ManufactureDate" }, + { 0x85, 0x0086, "SerialNumber" }, + { 0x85, 0x0087, "iManufacturerName" }, + { 0x85, 0x0088, "iDeviceName" }, + { 0x85, 0x0089, "iDeviceChemistry" }, + { 0x85, 0x008a, "ManufacturerData" }, + { 0x85, 0x008b, "Rechargable" }, + { 0x85, 0x008c, "WarningCapacityLimit" }, + { 0x85, 0x008d, "CapacityGranularity1" }, + { 0x85, 0x008e, "CapacityGranularity2" }, + { 0x85, 0x008f, "iOEMInformation" }, + { 0x85, 0x00c0, "InhibitCharge" }, + { 0x85, 0x00c1, "EnablePolling" }, + { 0x85, 0x00c2, "ResetToZero" }, + { 0x85, 0x00d0, "ACPresent" }, + { 0x85, 0x00d1, "BatteryPresent" }, + { 0x85, 0x00d2, "PowerFail" }, + { 0x85, 0x00d3, "AlarmInhibited" }, + { 0x85, 0x00d4, "ThermistorUnderRange" }, + { 0x85, 0x00d5, "ThermistorHot" }, + { 0x85, 0x00d6, "ThermistorCold" }, + { 0x85, 0x00d7, "ThermistorOverRange" }, + { 0x85, 0x00d8, "VoltageOutOfRange" }, + { 0x85, 0x00d9, "CurrentOutOfRange" }, + { 0x85, 0x00da, "CurrentNotRegulated" }, + { 0x85, 0x00db, "VoltageNotRegulated" }, + { 0x85, 0x00dc, "MasterMode" }, + { 0x85, 0x00f0, "ChargerSelectorSupport" }, + { 0x85, 0x00f1, "ChargerSpec" }, + { 0x85, 0x00f2, "Level2" }, + { 0x85, 0x00f3, "Level3" }, + { 0x8c, 0, "BarcodeScanner" }, + { 0x8c, 0x0001, "BarcodeBadgeReader" }, + { 0x8c, 0x0002, "BarcodeScanner" }, + { 0x8c, 0x0003, "DumbBarCodeScanner" }, + { 0x8c, 0x0004, "CordlessScannerBase" }, + { 0x8c, 0x0005, "BarCodeScannerCradle" }, + { 0x8c, 0x0010, "AttributeReport" }, + { 0x8c, 0x0011, "SettingsReport" }, + { 0x8c, 0x0012, "ScannedDataReport" }, + { 0x8c, 0x0013, "RawScannedDataReport" }, + { 0x8c, 0x0014, "TriggerReport" }, + { 0x8c, 0x0015, "StatusReport" }, + { 0x8c, 0x0016, "UPCEANControlReport" }, + { 0x8c, 0x0017, "EAN23LabelControlReport" }, + { 0x8c, 0x0018, "Code39ControlReport" }, + { 0x8c, 0x0019, "Interleaved2of5ControlReport" }, + { 0x8c, 0x001a, "Standard2of5ControlReport" }, + { 0x8c, 0x001b, "MSIPlesseyControlReport" }, + { 0x8c, 0x001c, "CodabarControlReport" }, + { 0x8c, 0x001d, "Code128ControlReport" }, + { 0x8c, 0x001e, "Misc1DControlReport" }, + { 0x8c, 0x001f, "2DControlReport" }, + { 0x8c, 0x0030, "AimingPointerMode" }, + { 0x8c, 0x0031, "BarCodePresentSensor" }, + { 0x8c, 0x0032, "Class1ALaser" }, + { 0x8c, 0x0033, "Class2Laser" }, + { 0x8c, 0x0034, "HeaterPresent" }, + { 0x8c, 0x0035, "ContactScanner" }, + { 0x8c, 0x0036, "ElectronicArticleSurveillanceNotification" }, + { 0x8c, 0x0037, "ConstantElectronicArticleSurveillance" }, + { 0x8c, 0x0038, "ErrorIndication" }, + { 0x8c, 0x0039, "FixedBeeper" }, + { 0x8c, 0x003a, "GoodDecodeIndication" }, + { 0x8c, 0x003b, "HandsFreeScanning" }, + { 0x8c, 0x003c, "IntrinsicallySafe" }, + { 0x8c, 0x003d, "KlasseEinsLaser" }, + { 0x8c, 0x003e, "LongRangeScanner" }, + { 0x8c, 0x003f, "MirrorSpeedControl" }, + { 0x8c, 0x0040, "NotOnFileIndication" }, + { 0x8c, 0x0041, "ProgrammableBeeper" }, + { 0x8c, 0x0042, "Triggerless" }, + { 0x8c, 0x0043, "Wand" }, + { 0x8c, 0x0044, "WaterResistant" }, + { 0x8c, 0x0045, "MultiRangeScanner" }, + { 0x8c, 0x0046, "ProximitySensor" }, + { 0x8c, 0x004d, "FragmentDecoding" }, + { 0x8c, 0x004e, "ScannerReadConfidence" }, + { 0x8c, 0x004f, "DataPrefix" }, + { 0x8c, 0x0050, "PrefixAIMI" }, + { 0x8c, 0x0051, "PrefixNone" }, + { 0x8c, 0x0052, "PrefixProprietary" }, + { 0x8c, 0x0055, "ActiveTime" }, + { 0x8c, 0x0056, "AimingLaserPattern" }, + { 0x8c, 0x0057, "BarCodePresent" }, + { 0x8c, 0x0058, "BeeperState" }, + { 0x8c, 0x0059, "LaserOnTime" }, + { 0x8c, 0x005a, "LaserState" }, + { 0x8c, 0x005b, "LockoutTime" }, + { 0x8c, 0x005c, "MotorState" }, + { 0x8c, 0x005d, "MotorTimeout" }, + { 0x8c, 0x005e, "PowerOnResetScanner" }, + { 0x8c, 0x005f, "PreventReadofBarcodes" }, + { 0x8c, 0x0060, "InitiateBarcodeRead" }, + { 0x8c, 0x0061, "TriggerState" }, + { 0x8c, 0x0062, "TriggerMode" }, + { 0x8c, 0x0063, "TriggerModeBlinkingLaserOn" }, + { 0x8c, 0x0064, "TriggerModeContinuousLaserOn" }, + { 0x8c, 0x0065, "TriggerModeLaseronwhilePulled" }, + { 0x8c, 0x0066, "TriggerModeLaserstaysonafterrelease" }, + { 0x8c, 0x006d, "CommitParameterstoNVM" }, + { 0x8c, 0x006e, "ParameterScanning" }, + { 0x8c, 0x006f, "ParametersChanged" }, + { 0x8c, 0x0070, "Setparameterdefaultvalues" }, + { 0x8c, 0x0075, "ScannerInCradle" }, + { 0x8c, 0x0076, "ScannerInRange" }, + { 0x8c, 0x007a, "AimDuration" }, + { 0x8c, 0x007b, "GoodReadLampDuration" }, + { 0x8c, 0x007c, "GoodReadLampIntensity" }, + { 0x8c, 0x007d, "GoodReadLED" }, + { 0x8c, 0x007e, "GoodReadToneFrequency" }, + { 0x8c, 0x007f, "GoodReadToneLength" }, + { 0x8c, 0x0080, "GoodReadToneVolume" }, + { 0x8c, 0x0082, "NoReadMessage" }, + { 0x8c, 0x0083, "NotonFileVolume" }, + { 0x8c, 0x0084, "PowerupBeep" }, + { 0x8c, 0x0085, "SoundErrorBeep" }, + { 0x8c, 0x0086, "SoundGoodReadBeep" }, + { 0x8c, 0x0087, "SoundNotOnFileBeep" }, + { 0x8c, 0x0088, "GoodReadWhentoWrite" }, + { 0x8c, 0x0089, "GRWTIAfterDecode" }, + { 0x8c, 0x008a, "GRWTIBeepLampaftertransmit" }, + { 0x8c, 0x008b, "GRWTINoBeepLampuseatall" }, + { 0x8c, 0x0091, "BooklandEAN" }, + { 0x8c, 0x0092, "ConvertEAN8to13Type" }, + { 0x8c, 0x0093, "ConvertUPCAtoEAN13" }, + { 0x8c, 0x0094, "ConvertUPCEtoA" }, + { 0x8c, 0x0095, "EAN13" }, + { 0x8c, 0x0096, "EAN8" }, + { 0x8c, 0x0097, "EAN99128Mandatory" }, + { 0x8c, 0x0098, "EAN99P5128Optional" }, + { 0x8c, 0x0099, "EnableEANTwoLabel" }, + { 0x8c, 0x009a, "UPCEAN" }, + { 0x8c, 0x009b, "UPCEANCouponCode" }, + { 0x8c, 0x009c, "UPCEANPeriodicals" }, + { 0x8c, 0x009d, "UPCA" }, + { 0x8c, 0x009e, "UPCAwith128Mandatory" }, + { 0x8c, 0x009f, "UPCAwith128Optional" }, + { 0x8c, 0x00a0, "UPCAwithP5Optional" }, + { 0x8c, 0x00a1, "UPCE" }, + { 0x8c, 0x00a2, "UPCE1" }, + { 0x8c, 0x00a9, "Periodical" }, + { 0x8c, 0x00aa, "PeriodicalAutoDiscriminate2" }, + { 0x8c, 0x00ab, "PeriodicalOnlyDecodewith2" }, + { 0x8c, 0x00ac, "PeriodicalIgnore2" }, + { 0x8c, 0x00ad, "PeriodicalAutoDiscriminate5" }, + { 0x8c, 0x00ae, "PeriodicalOnlyDecodewith5" }, + { 0x8c, 0x00af, "PeriodicalIgnore5" }, + { 0x8c, 0x00b0, "Check" }, + { 0x8c, 0x00b1, "CheckDisablePrice" }, + { 0x8c, 0x00b2, "CheckEnable4digitPrice" }, + { 0x8c, 0x00b3, "CheckEnable5digitPrice" }, + { 0x8c, 0x00b4, "CheckEnableEuropean4digitPrice" }, + { 0x8c, 0x00b5, "CheckEnableEuropean5digitPrice" }, + { 0x8c, 0x00b7, "EANTwoLabel" }, + { 0x8c, 0x00b8, "EANThreeLabel" }, + { 0x8c, 0x00b9, "EAN8FlagDigit1" }, + { 0x8c, 0x00ba, "EAN8FlagDigit2" }, + { 0x8c, 0x00bb, "EAN8FlagDigit3" }, + { 0x8c, 0x00bc, "EAN13FlagDigit1" }, + { 0x8c, 0x00bd, "EAN13FlagDigit2" }, + { 0x8c, 0x00be, "EAN13FlagDigit3" }, + { 0x8c, 0x00bf, "AddEAN23LabelDefinition" }, + { 0x8c, 0x00c0, "ClearallEAN23LabelDefinitions" }, + { 0x8c, 0x00c3, "Codabar" }, + { 0x8c, 0x00c4, "Code128" }, + { 0x8c, 0x00c7, "Code39" }, + { 0x8c, 0x00c8, "Code93" }, + { 0x8c, 0x00c9, "FullASCIIConversion" }, + { 0x8c, 0x00ca, "Interleaved2of5" }, + { 0x8c, 0x00cb, "ItalianPharmacyCode" }, + { 0x8c, 0x00cc, "MSIPlessey" }, + { 0x8c, 0x00cd, "Standard2of5IATA" }, + { 0x8c, 0x00ce, "Standard2of5" }, + { 0x8c, 0x00d3, "TransmitStartStop" }, + { 0x8c, 0x00d4, "TriOptic" }, + { 0x8c, 0x00d5, "UCCEAN128" }, + { 0x8c, 0x00d6, "CheckDigit" }, + { 0x8c, 0x00d7, "CheckDigitDisable" }, + { 0x8c, 0x00d8, "CheckDigitEnableInterleaved2of5OPCC" }, + { 0x8c, 0x00d9, "CheckDigitEnableInterleaved2of5USS" }, + { 0x8c, 0x00da, "CheckDigitEnableStandard2of5OPCC" }, + { 0x8c, 0x00db, "CheckDigitEnableStandard2of5USS" }, + { 0x8c, 0x00dc, "CheckDigitEnableOneMSIPlessey" }, + { 0x8c, 0x00dd, "CheckDigitEnableTwoMSIPlessey" }, + { 0x8c, 0x00de, "CheckDigitCodabarEnable" }, + { 0x8c, 0x00df, "CheckDigitCode39Enable" }, + { 0x8c, 0x00f0, "TransmitCheckDigit" }, + { 0x8c, 0x00f1, "DisableCheckDigitTransmit" }, + { 0x8c, 0x00f2, "EnableCheckDigitTransmit" }, + { 0x8c, 0x00fb, "SymbologyIdentifier1" }, + { 0x8c, 0x00fc, "SymbologyIdentifier2" }, + { 0x8c, 0x00fd, "SymbologyIdentifier3" }, + { 0x8c, 0x00fe, "DecodedData" }, + { 0x8c, 0x00ff, "DecodeDataContinued" }, + { 0x8c, 0x0100, "BarSpaceData" }, + { 0x8c, 0x0101, "ScannerDataAccuracy" }, + { 0x8c, 0x0102, "RawDataPolarity" }, + { 0x8c, 0x0103, "PolarityInvertedBarCode" }, + { 0x8c, 0x0104, "PolarityNormalBarCode" }, + { 0x8c, 0x0106, "MinimumLengthtoDecode" }, + { 0x8c, 0x0107, "MaximumLengthtoDecode" }, + { 0x8c, 0x0108, "DiscreteLengthtoDecode1" }, + { 0x8c, 0x0109, "DiscreteLengthtoDecode2" }, + { 0x8c, 0x010a, "DataLengthMethod" }, + { 0x8c, 0x010b, "DLMethodReadany" }, + { 0x8c, 0x010c, "DLMethodCheckinRange" }, + { 0x8c, 0x010d, "DLMethodCheckforDiscrete" }, + { 0x8c, 0x0110, "AztecCode" }, + { 0x8c, 0x0111, "BC412" }, + { 0x8c, 0x0112, "ChannelCode" }, + { 0x8c, 0x0113, "Code16" }, + { 0x8c, 0x0114, "Code32" }, + { 0x8c, 0x0115, "Code49" }, + { 0x8c, 0x0116, "CodeOne" }, + { 0x8c, 0x0117, "Colorcode" }, + { 0x8c, 0x0118, "DataMatrix" }, + { 0x8c, 0x0119, "MaxiCode" }, + { 0x8c, 0x011a, "MicroPDF" }, + { 0x8c, 0x011b, "PDF417" }, + { 0x8c, 0x011c, "PosiCode" }, + { 0x8c, 0x011d, "QRCode" }, + { 0x8c, 0x011e, "SuperCode" }, + { 0x8c, 0x011f, "UltraCode" }, + { 0x8c, 0x0120, "USD5SlugCode" }, + { 0x8c, 0x0121, "VeriCode" }, + { 0x8d, 0, "Scales" }, + { 0x8d, 0x0001, "Scales" }, + { 0x8d, 0x0020, "ScaleDevice" }, + { 0x8d, 0x0021, "ScaleClass" }, + { 0x8d, 0x0022, "ScaleClassIMetric" }, + { 0x8d, 0x0023, "ScaleClassIIMetric" }, + { 0x8d, 0x0024, "ScaleClassIIIMetric" }, + { 0x8d, 0x0025, "ScaleClassIIILMetric" }, + { 0x8d, 0x0026, "ScaleClassIVMetric" }, + { 0x8d, 0x0027, "ScaleClassIIIEnglish" }, + { 0x8d, 0x0028, "ScaleClassIIILEnglish" }, + { 0x8d, 0x0029, "ScaleClassIVEnglish" }, + { 0x8d, 0x002a, "ScaleClassGeneric" }, + { 0x8d, 0x0030, "ScaleAttributeReport" }, + { 0x8d, 0x0031, "ScaleControlReport" }, + { 0x8d, 0x0032, "ScaleDataReport" }, + { 0x8d, 0x0033, "ScaleStatusReport" }, + { 0x8d, 0x0034, "ScaleWeightLimitReport" }, + { 0x8d, 0x0035, "ScaleStatisticsReport" }, + { 0x8d, 0x0040, "DataWeight" }, + { 0x8d, 0x0041, "DataScaling" }, + { 0x8d, 0x0050, "WeightUnit" }, + { 0x8d, 0x0051, "WeightUnitMilligram" }, + { 0x8d, 0x0052, "WeightUnitGram" }, + { 0x8d, 0x0053, "WeightUnitKilogram" }, + { 0x8d, 0x0054, "WeightUnitCarats" }, + { 0x8d, 0x0055, "WeightUnitTaels" }, + { 0x8d, 0x0056, "WeightUnitGrains" }, + { 0x8d, 0x0057, "WeightUnitPennyweights" }, + { 0x8d, 0x0058, "WeightUnitMetricTon" }, + { 0x8d, 0x0059, "WeightUnitAvoirTon" }, + { 0x8d, 0x005a, "WeightUnitTroyOunce" }, + { 0x8d, 0x005b, "WeightUnitOunce" }, + { 0x8d, 0x005c, "WeightUnitPound" }, + { 0x8d, 0x0060, "CalibrationCount" }, + { 0x8d, 0x0061, "ReZeroCount" }, + { 0x8d, 0x0070, "ScaleStatus" }, + { 0x8d, 0x0071, "ScaleStatusFault" }, + { 0x8d, 0x0072, "ScaleStatusStableatCenterofZero" }, + { 0x8d, 0x0073, "ScaleStatusInMotion" }, + { 0x8d, 0x0074, "ScaleStatusWeightStable" }, + { 0x8d, 0x0075, "ScaleStatusUnderZero" }, + { 0x8d, 0x0076, "ScaleStatusOverWeightLimit" }, + { 0x8d, 0x0077, "ScaleStatusRequiresCalibration" }, + { 0x8d, 0x0078, "ScaleStatusRequiresRezeroing" }, + { 0x8d, 0x0080, "ZeroScale" }, + { 0x8d, 0x0081, "EnforcedZeroReturn" }, + { 0x8e, 0, "MagneticStripeReader" }, + { 0x8e, 0x0001, "MSRDeviceReadOnly" }, + { 0x8e, 0x0011, "Track1Length" }, + { 0x8e, 0x0012, "Track2Length" }, + { 0x8e, 0x0013, "Track3Length" }, + { 0x8e, 0x0014, "TrackJISLength" }, + { 0x8e, 0x0020, "TrackData" }, + { 0x8e, 0x0021, "Track1Data" }, + { 0x8e, 0x0022, "Track2Data" }, + { 0x8e, 0x0023, "Track3Data" }, + { 0x8e, 0x0024, "TrackJISData" }, + { 0x90, 0, "CameraControl" }, + { 0x90, 0x0020, "CameraAutofocus" }, + { 0x90, 0x0021, "CameraShutter" }, + { 0x91, 0, "Arcade" }, + { 0x91, 0x0001, "GeneralPurposeIOCard" }, + { 0x91, 0x0002, "CoinDoor" }, + { 0x91, 0x0003, "WatchdogTimer" }, + { 0x91, 0x0030, "GeneralPurposeAnalogInputState" }, + { 0x91, 0x0031, "GeneralPurposeDigitalInputState" }, + { 0x91, 0x0032, "GeneralPurposeOpticalInputState" }, + { 0x91, 0x0033, "GeneralPurposeDigitalOutputState" }, + { 0x91, 0x0034, "NumberofCoinDoors" }, + { 0x91, 0x0035, "CoinDrawerDropCount" }, + { 0x91, 0x0036, "CoinDrawerStart" }, + { 0x91, 0x0037, "CoinDrawerService" }, + { 0x91, 0x0038, "CoinDrawerTilt" }, + { 0x91, 0x0039, "CoinDoorTest" }, + { 0x91, 0x0040, "CoinDoorLockout" }, + { 0x91, 0x0041, "WatchdogTimeout" }, + { 0x91, 0x0042, "WatchdogAction" }, + { 0x91, 0x0043, "WatchdogReboot" }, + { 0x91, 0x0044, "WatchdogRestart" }, + { 0x91, 0x0045, "AlarmInput" }, + { 0x91, 0x0046, "CoinDoorCounter" }, + { 0x91, 0x0047, "IODirectionMapping" }, + { 0x91, 0x0048, "SetIODirectionMapping" }, + { 0x91, 0x0049, "ExtendedOpticalInputState" }, + { 0x91, 0x004a, "PinPadInputState" }, + { 0x91, 0x004b, "PinPadStatus" }, + { 0x91, 0x004c, "PinPadOutput" }, + { 0x91, 0x004d, "PinPadCommand" }, + { 0xf1d0, 0, "FIDOAlliance" }, + { 0xf1d0, 0x0001, "U2FAuthenticatorDevice" }, + { 0xf1d0, 0x0020, "InputReportData" }, + { 0xf1d0, 0x0021, "OutputReportData" }, + /* pages 0xff00 to 0xffff are vendor-specific */ + { 0xffff, 0, "Vendor-specific-FF" }, + { 0, 0, NULL } }; /* Either output directly into simple seq_file, or (if f == NULL) @@ -510,8 +2881,12 @@ static char *resolv_usage_page(unsigned page, struct seq_file *f) { char *hid_resolv_usage(unsigned usage, struct seq_file *f) { const struct hid_usage_entry *p; + const struct hid_usage_entry *m; char *buf = NULL; int len = 0; + const char *modifier = NULL; + unsigned int usage_modifier = usage & 0xF000; + unsigned int usage_actual = usage & 0xFFFF; buf = resolv_usage_page(usage >> 16, f); if (IS_ERR(buf)) { @@ -529,16 +2904,33 @@ char *hid_resolv_usage(unsigned usage, struct seq_file *f) { } for (p = hid_usage_table; p->description; p++) if (p->page == (usage >> 16)) { + if (p->page == 0x20 && usage_modifier) { + for (m = p; m->description; m++) { + if (p->page == m->page && m->usage + == usage_modifier) { + modifier = m->description; + break; + } + } + if (modifier) + usage_actual = usage_actual & 0x0FFF; + } + + if (!modifier) + modifier = ""; + for(++p; p->description && p->usage != 0; p++) - if (p->usage == (usage & 0xffff)) { + if (p->usage == usage_actual) { if (!f) snprintf(buf + len, HID_DEBUG_BUFSIZE - len, - "%s", p->description); + "%s%s", p->description, + modifier); else seq_printf(f, - "%s", - p->description); + "%s%s", + p->description, + modifier); return buf; } break; @@ -753,12 +3145,12 @@ static const char *events[EV_MAX + 1] = { [EV_MSC] = "Misc", [EV_LED] = "LED", [EV_SND] = "Sound", [EV_REP] = "Repeat", [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", - [EV_FF_STATUS] = "ForceFeedbackStatus", + [EV_FF_STATUS] = "ForceFeedbackStatus", [EV_SW] = "Software", }; -static const char *syncs[3] = { +static const char *syncs[SYN_CNT] = { [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", - [SYN_MT_REPORT] = "MT Report", + [SYN_MT_REPORT] = "MT Report", [SYN_DROPPED] = "Dropped", }; static const char *keys[KEY_MAX + 1] = { @@ -995,6 +3387,103 @@ static const char *keys[KEY_MAX + 1] = { [KEY_MACRO22] = "Macro22", [KEY_MACRO23] = "Macro23", [KEY_MACRO24] = "Macro24", [KEY_MACRO25] = "Macro25", [KEY_MACRO26] = "Macro26", [KEY_MACRO27] = "Macro27", [KEY_MACRO28] = "Macro28", [KEY_MACRO29] = "Macro29", [KEY_MACRO30] = "Macro30", + [BTN_TRIGGER_HAPPY1] = "TriggerHappy1", [BTN_TRIGGER_HAPPY2] = "TriggerHappy2", + [BTN_TRIGGER_HAPPY3] = "TriggerHappy3", [BTN_TRIGGER_HAPPY4] = "TriggerHappy4", + [BTN_TRIGGER_HAPPY5] = "TriggerHappy5", [BTN_TRIGGER_HAPPY6] = "TriggerHappy6", + [BTN_TRIGGER_HAPPY7] = "TriggerHappy7", [BTN_TRIGGER_HAPPY8] = "TriggerHappy8", + [BTN_TRIGGER_HAPPY9] = "TriggerHappy9", [BTN_TRIGGER_HAPPY10] = "TriggerHappy10", + [BTN_TRIGGER_HAPPY11] = "TriggerHappy11", [BTN_TRIGGER_HAPPY12] = "TriggerHappy12", + [BTN_TRIGGER_HAPPY13] = "TriggerHappy13", [BTN_TRIGGER_HAPPY14] = "TriggerHappy14", + [BTN_TRIGGER_HAPPY15] = "TriggerHappy15", [BTN_TRIGGER_HAPPY16] = "TriggerHappy16", + [BTN_TRIGGER_HAPPY17] = "TriggerHappy17", [BTN_TRIGGER_HAPPY18] = "TriggerHappy18", + [BTN_TRIGGER_HAPPY19] = "TriggerHappy19", [BTN_TRIGGER_HAPPY20] = "TriggerHappy20", + [BTN_TRIGGER_HAPPY21] = "TriggerHappy21", [BTN_TRIGGER_HAPPY22] = "TriggerHappy22", + [BTN_TRIGGER_HAPPY23] = "TriggerHappy23", [BTN_TRIGGER_HAPPY24] = "TriggerHappy24", + [BTN_TRIGGER_HAPPY25] = "TriggerHappy25", [BTN_TRIGGER_HAPPY26] = "TriggerHappy26", + [BTN_TRIGGER_HAPPY27] = "TriggerHappy27", [BTN_TRIGGER_HAPPY28] = "TriggerHappy28", + [BTN_TRIGGER_HAPPY29] = "TriggerHappy29", [BTN_TRIGGER_HAPPY30] = "TriggerHappy30", + [BTN_TRIGGER_HAPPY31] = "TriggerHappy31", [BTN_TRIGGER_HAPPY32] = "TriggerHappy32", + [BTN_TRIGGER_HAPPY33] = "TriggerHappy33", [BTN_TRIGGER_HAPPY34] = "TriggerHappy34", + [BTN_TRIGGER_HAPPY35] = "TriggerHappy35", [BTN_TRIGGER_HAPPY36] = "TriggerHappy36", + [BTN_TRIGGER_HAPPY37] = "TriggerHappy37", [BTN_TRIGGER_HAPPY38] = "TriggerHappy38", + [BTN_TRIGGER_HAPPY39] = "TriggerHappy39", [BTN_TRIGGER_HAPPY40] = "TriggerHappy40", + [BTN_DIGI] = "Digi", [BTN_STYLUS3] = "Stylus3", + [BTN_TOOL_QUINTTAP] = "ToolQuintTap", [BTN_WHEEL] = "Wheel", + [KEY_10CHANNELSDOWN] = "10ChannelsDown", + [KEY_10CHANNELSUP] = "10ChannelsUp", + [KEY_3D_MODE] = "3DMode", [KEY_ADDRESSBOOK] = "Addressbook", + [KEY_ALS_TOGGLE] = "ALSToggle", [KEY_ASPECT_RATIO] = "AspectRatio", + [KEY_ATTENDANT_OFF] = "AttendantOff", [KEY_ATTENDANT_ON] = "AttendantOn", + [KEY_ATTENDANT_TOGGLE] = "AttendantToggle", + [KEY_AUDIO_DESC] = "AudioDesc", + [KEY_AUTOPILOT_ENGAGE_TOGGLE] = "AutoPiloteEngage", + [KEY_BATTERY] = "Battery", [KEY_BLUETOOTH] = "BlueTooth", + [KEY_BRIGHTNESS_CYCLE] = "BrightnessCycle", + [KEY_BRIGHTNESS_MENU] = "BrightnessMenu", + [KEY_BRL_DOT1] = "BrlDot1", [KEY_BRL_DOT10] = "BrlDot10", + [KEY_BRL_DOT2] = "BrlDot2", [KEY_BRL_DOT3] = "BrlDot3", + [KEY_BRL_DOT4] = "BrlDot4", [KEY_BRL_DOT5] = "BrlDot5", + [KEY_BRL_DOT6] = "BrlDot6", [KEY_BRL_DOT7] = "BrlDot7", + [KEY_BRL_DOT8] = "BrlDot8", [KEY_BRL_DOT9] = "BrlDot9", + [KEY_CAMERA_DOWN] = "CameraDown", [KEY_CAMERA_FOCUS] = "CameraFocus", + [KEY_CAMERA_LEFT] = "CameraLeft", [KEY_CAMERA_RIGHT] = "CameraRight", + [KEY_CAMERA_UP] = "CameraUp", [KEY_CAMERA_ZOOMIN] = "CameraZoomIn", + [KEY_CAMERA_ZOOMOUT] = "CameraZoomOut", [KEY_CLEARVU_SONAR] = "ClearVUSonar", + [KEY_CONTEXT_MENU] = "ContextMenu", [KEY_DATA] = "Data", + [KEY_DATABASE] = "DataBase", [KEY_DISPLAY_OFF] = "DisplayOff", + [KEY_DISPLAYTOGGLE] = "DisplayToggle", [KEY_DOLLAR] = "Dollar", + [KEY_DUAL_RANGE_RADAR] = "DualRangeRadat", + [KEY_EDITOR] = "Editor", [KEY_EURO] = "Euro", + [KEY_FASTREVERSE] = "FastReverse", [KEY_FISHING_CHART] = "FishingChart", + [KEY_FN_RIGHT_SHIFT] = "FnRightShift", [KEY_FRAMEBACK] = "FrameBack", + [KEY_FRAMEFORWARD] = "FrameForward", [KEY_FULL_SCREEN] = "FullScreen", + [KEY_GAMES] = "Games", [KEY_GRAPHICSEDITOR] = "GraphicsEditor", + [KEY_HANGEUL] = "HanGeul", [KEY_HANGUP_PHONE] = "HangUpPhone", + [KEY_IMAGES] = "Images", [KEY_KBD_LCD_MENU1] = "KbdLcdMenu1", + [KEY_KBD_LCD_MENU2] = "KbdLcdMenu2", [KEY_KBD_LCD_MENU3] = "KbdLcdMenu3", + [KEY_KBD_LCD_MENU4] = "KbdLcdMenu4", [KEY_KBD_LCD_MENU5] = "KbdLcdMenu5", + [KEY_LEFT_DOWN] = "LeftDown", [KEY_LEFT_UP] = "LeftUp", + [KEY_LIGHTS_TOGGLE] = "LightToggle", [KEY_MACRO_PRESET1] = "MacroPreset1", + [KEY_MACRO_PRESET2] = "MacroPreset2", [KEY_MACRO_PRESET3] = "MacroPrest3", + [KEY_MACRO_PRESET_CYCLE] = "MacroPresetCycle", + [KEY_MACRO_RECORD_START] = "MacroRecordStart", + [KEY_MACRO_RECORD_STOP] = "MacroRecordStop", + [KEY_MARK_WAYPOINT] = "MarkWayPoint", [KEY_MEDIA_REPEAT] = "MediaRepeat", + [KEY_MEDIA_TOP_MENU] = "MediaTopMenu", [KEY_MESSENGER] = "Messanger", + [KEY_NAV_CHART] = "NavChar", [KEY_NAV_INFO] = "NavInfo", + [KEY_NEWS] = "News", [KEY_NEXT_ELEMENT] = "NextElement", + [KEY_NEXT_FAVORITE] = "NextFavorite", [KEY_NOTIFICATION_CENTER] = "NotificationCenter", + [KEY_NUMERIC_0] = "Numeric0", [KEY_NUMERIC_1] = "Numeric1", + [KEY_NUMERIC_11] = "Numceric11", [KEY_NUMERIC_12] = "Numeric12", + [KEY_NUMERIC_2] = "Numeric2", [KEY_NUMERIC_3] = "Numeric3", + [KEY_NUMERIC_4] = "Numeric4", [KEY_NUMERIC_5] = "Numeric5", + [KEY_NUMERIC_6] = "Numeric6", [KEY_NUMERIC_7] = "Numeric7", + [KEY_NUMERIC_8] = "Numeric8", [KEY_NUMERIC_9] = "Numeric9", + [KEY_NUMERIC_A] = "NumericA", [KEY_NUMERIC_B] = "NumericB", + [KEY_NUMERIC_C] = "NumericC", [KEY_NUMERIC_D] = "NumericD", + [KEY_NUMERIC_POUND] = "NumericPound", [KEY_NUMERIC_STAR] = "NumericStar", + [KEY_ONSCREEN_KEYBOARD] = "OnScreenKeyBoard", + [KEY_PAUSE_RECORD] = "PauseRecord", [KEY_PICKUP_PHONE] = "PickUpPhone", + [KEY_PRESENTATION] = "Presentation", [KEY_PREVIOUS_ELEMENT] = "PreviousElement", + [KEY_PRIVACY_SCREEN_TOGGLE] = "PrivacyScreenToggle", + [KEY_RADAR_OVERLAY] = "RadarOverLay", + [KEY_RFKILL] = "RFKill", [KEY_RIGHT_DOWN] = "RightDown", + [KEY_RIGHT_UP] = "RightUp", [KEY_ROOT_MENU] = "RootMenu", + [KEY_ROTATE_LOCK_TOGGLE] = "RotateLockToggle", + [KEY_SCALE] = "Scale", [KEY_SELECTIVE_SCREENSHOT] = "SelectiveScreenshot", + [KEY_SIDEVU_SONAR] = "SideVUSonar", [KEY_SINGLE_RANGE_RADAR] = "SingleRangeRadar", + [KEY_SLOWREVERSE] = "SlowReverse", [KEY_SOS] = "SOS", + [KEY_SPREADSHEET] = "SpreadSheet", [KEY_STOP_RECORD] = "StopRecord", + [KEY_TOUCHPAD_OFF] = "TouchPadOff", [KEY_TOUCHPAD_ON] = "TouchPadOn", + [KEY_TOUCHPAD_TOGGLE] = "TouchPadToggle", + [KEY_TRADITIONAL_SONAR] = "TraditionalSonar", + [KEY_UNMUTE] = "Unmute", [KEY_UWB] = "UWB", + [KEY_VIDEO_NEXT] = "VideoNext", [KEY_VIDEOPHONE] = "VideoPhone", + [KEY_VIDEO_PREV] = "VideoPrev", [KEY_VOD] = "VOD", + [KEY_VOICEMAIL] = "VoiceMail", [KEY_WLAN] = "WLAN", + [KEY_WORDPROCESSOR] = "WordProcessor", [KEY_WPS_BUTTON] = "WPSButton", + [KEY_WWAN] = "WWAN", [KEY_ZOOMIN] = "ZoomIn", + [KEY_ZOOMOUT] = "ZoomOut", [KEY_ZOOMRESET] = "ZoomReset", }; static const char *relatives[REL_MAX + 1] = { @@ -1003,6 +3492,8 @@ static const char *relatives[REL_MAX + 1] = { [REL_RY] = "Ry", [REL_RZ] = "Rz", [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", + [REL_WHEEL_HI_RES] = "WheelHiRes", + [REL_HWHEEL_HI_RES] = "HWheelHiRes" }; static const char *absolutes[ABS_CNT] = { @@ -1020,6 +3511,7 @@ static const char *absolutes[ABS_CNT] = { [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "ToolWidth", [ABS_VOLUME] = "Volume", [ABS_PROFILE] = "Profile", [ABS_MISC] = "Misc", + [ABS_MT_SLOT] = "MTSlot", [ABS_MT_TOUCH_MAJOR] = "MTMajor", [ABS_MT_TOUCH_MINOR] = "MTMinor", [ABS_MT_WIDTH_MAJOR] = "MTMajorW", @@ -1029,11 +3521,17 @@ static const char *absolutes[ABS_CNT] = { [ABS_MT_POSITION_Y] = "MTPositionY", [ABS_MT_TOOL_TYPE] = "MTToolType", [ABS_MT_BLOB_ID] = "MTBlobID", + [ABS_MT_TRACKING_ID] = "MTTrackingID", + [ABS_MT_PRESSURE] = "MTPressure", + [ABS_MT_DISTANCE] = "MTDistance", + [ABS_MT_TOOL_X] = "MTToolX", + [ABS_MT_TOOL_Y] = "MTToolY", }; static const char *misc[MSC_MAX + 1] = { [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", - [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" + [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData", + [MSC_SCAN] = "Scan", [MSC_TIMESTAMP] = "TimeStamp", }; static const char *leds[LED_MAX + 1] = { @@ -1041,7 +3539,8 @@ static const char *leds[LED_MAX + 1] = { [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", - [LED_MISC] = "Misc", + [LED_MISC] = "Misc", [LED_MAIL] = "Mail", + [LED_CHARGING] = "Charging", }; static const char *repeats[REP_MAX + 1] = { @@ -1053,11 +3552,32 @@ static const char *sounds[SND_MAX + 1] = { [SND_TONE] = "Tone" }; +static const char *software[SW_CNT] = { + [SW_LID] = "Lid", + [SW_TABLET_MODE] = "TabletMode", + [SW_HEADPHONE_INSERT] = "HeadPhoneInsert", + [SW_RFKILL_ALL] = "RFKillAll", + [SW_MICROPHONE_INSERT] = "MicrophoneInsert", + [SW_DOCK] = "Dock", + [SW_LINEOUT_INSERT] = "LineOutInsert", + [SW_JACK_PHYSICAL_INSERT] = "JackPhysicalInsert", + [SW_VIDEOOUT_INSERT] = "VideoOutInsert", + [SW_CAMERA_LENS_COVER] = "CameraLensCover", + [SW_KEYPAD_SLIDE] = "KeyPadSlide", + [SW_FRONT_PROXIMITY] = "FrontProximity", + [SW_ROTATE_LOCK] = "RotateLock", + [SW_LINEIN_INSERT] = "LineInInsert", + [SW_MUTE_DEVICE] = "MuteDevice", + [SW_PEN_INSERTED] = "PenInserted", + [SW_MACHINE_COVER] = "MachineCover", +}; + static const char **names[EV_MAX + 1] = { [EV_SYN] = syncs, [EV_KEY] = keys, [EV_REL] = relatives, [EV_ABS] = absolutes, [EV_MSC] = misc, [EV_LED] = leds, [EV_SND] = sounds, [EV_REP] = repeats, + [EV_SW] = software, }; static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) -- cgit v1.2.3 From a721b1423b049323d0987700ff125b46208046f9 Mon Sep 17 00:00:00 2001 From: José Expósito Date: Fri, 22 Mar 2024 10:59:58 +0100 Subject: HID: uclogic: Expose firmware name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some vendors reuse the same product ID for different tablets, making it difficult for userspace to figure out which table is connected. While matching the device name has been used in the past by userspace to workaround this limitation, some devices have shown that this is not always a valid approach [1]. However, if userspace could access the firmware version name, it would be possible to know which tablet is actually connected by matching it against a list of known firmware names [2]. This patch exposes the firmware version name in the hid->uniq field. Link: https://github.com/linuxwacom/libwacom/issues/609 [1] Link: https://github.com/linuxwacom/libwacom/issues/610 [2] Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 9859dad36495..5bab006ec165 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -884,6 +884,9 @@ static int uclogic_params_huion_init(struct uclogic_params *params, goto cleanup; } + /* The firmware is used in userspace as unique identifier */ + strscpy(hdev->uniq, ver_ptr, sizeof(hdev->uniq)); + /* If this is a transition firmware */ if (strcmp(ver_ptr, transition_ver) == 0) { hid_dbg(hdev, -- cgit v1.2.3 From 8f39af37eb18b03cbd5ea3b01c8eea26280b3b3f Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Thu, 8 Feb 2024 01:36:43 +0900 Subject: HID: playstation: DS4: Fix LED blinking There was no way to disable blinking once enabled. Disable it on brightness = 0, as per the Linux LED spec. The driver reports back the values it sends to the controller, but they need to be scaled back to milliseconds. Setting the LED blinking via sysfs works as expected now. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 8ac8f7b8e317..7f50e13601f0 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -2037,8 +2037,9 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del dualshock4_schedule_work(ds4); - *delay_on = ds4->lightbar_blink_on; - *delay_off = ds4->lightbar_blink_off; + /* Report scaled values back to LED subsystem */ + *delay_on = ds4->lightbar_blink_on * 10; + *delay_off = ds4->lightbar_blink_off * 10; return 0; } @@ -2065,6 +2066,13 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig break; case 3: ds4->lightbar_enabled = !!value; + + /* brightness = 0 also cancels blinking in Linux. */ + if (!ds4->lightbar_enabled) { + ds4->lightbar_blink_off = 0; + ds4->lightbar_blink_on = 0; + ds4->update_lightbar_blink = true; + } } ds4->update_lightbar = true; -- cgit v1.2.3 From 46089080a8e1c9a16c5967063986f31031bd218f Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Thu, 8 Feb 2024 01:36:44 +0900 Subject: HID: playstation: DS4: Don't fail on FW/HW version request Some third-party controllers can't report firmware/hardware version. Unlike for the DualSense, the driver does not use these values for anything in the DualShock 4 case, but merely exposes them via sysfs. They will simply be 0x0. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 7f50e13601f0..df50ca4dab90 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -2558,8 +2558,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) ret = dualshock4_get_firmware_info(ds4); if (ret) { - hid_err(hdev, "Failed to get firmware info from DualShock4\n"); - return ERR_PTR(ret); + hid_warn(hdev, "Failed to get firmware info from DualShock4\n"); + hid_warn(hdev, "HW/FW version data in sysfs will be invalid.\n"); } ret = ps_devices_list_add(ps_dev); -- cgit v1.2.3 From a48a7cd85f5518d21525642391602ec734cb100f Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Thu, 8 Feb 2024 01:36:45 +0900 Subject: HID: playstation: DS4: Don't fail on calibration data request Some third-party controllers can't report calibration data for the gyro/accelerometer. We can still use the gamepad as-is, so let's do that. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index df50ca4dab90..53bfc2828a61 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1778,8 +1778,10 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) int retries; buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + goto no_buffer_tail_check; + } /* We should normally receive the feature report data we asked * for, but hidraw applications such as Steam can issue feature @@ -1796,26 +1798,27 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) continue; } - hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); + hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); ret = -EILSEQ; - goto err_free; } else { break; } } } else { /* Bluetooth */ buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + goto no_buffer_tail_check; + } ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf, DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true); - if (ret) { - hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); - goto err_free; - } + + if (ret) + hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); } + /* Parse buffer. If the transfer failed, this safely copies zeroes. */ gyro_pitch_bias = get_unaligned_le16(&buf[1]); gyro_yaw_bias = get_unaligned_le16(&buf[3]); gyro_roll_bias = get_unaligned_le16(&buf[5]); @@ -1867,6 +1870,11 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); + /* Done parsing the buffer, so let's free it. */ + kfree(buf); + +no_buffer_tail_check: + /* * Sanity check gyro calibration data. This is needed to prevent crashes * during report handling of virtual, clone or broken devices not implementing @@ -1919,8 +1927,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) } } -err_free: - kfree(buf); return ret; } @@ -2568,8 +2574,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) ret = dualshock4_get_calibration_data(ds4); if (ret) { - hid_err(hdev, "Failed to get calibration data from DualShock4\n"); - goto err; + hid_warn(hdev, "Failed to get calibration data from DualShock4\n"); + hid_warn(hdev, "Gyroscope and accelerometer will be inaccurate.\n"); } ds4->gamepad = ps_gamepad_create(hdev, dualshock4_play_effect); -- cgit v1.2.3 From c7593026522a92a4fa4264a2f33b57a0d5addb6c Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Thu, 8 Feb 2024 01:36:46 +0900 Subject: HID: playstation: DS4: Parse minimal report 0x01 Some third-party controllers never switch to the full 0x11 report. They keep sending the short 0x01 report, so let's parse that instead. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 53bfc2828a61..6b0f25688657 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -287,6 +287,8 @@ struct dualsense_output_report { #define DS4_INPUT_REPORT_USB 0x01 #define DS4_INPUT_REPORT_USB_SIZE 64 +#define DS4_INPUT_REPORT_BT_MINIMAL 0x01 +#define DS4_INPUT_REPORT_BT_MINIMAL_SIZE 10 #define DS4_INPUT_REPORT_BT 0x11 #define DS4_INPUT_REPORT_BT_SIZE 78 #define DS4_OUTPUT_REPORT_USB 0x05 @@ -2196,6 +2198,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * int battery_status, i, j; uint16_t sensor_timestamp; unsigned long flags; + bool is_minimal = false; /* * DualShock4 in USB uses the full HID report for reportID 1, but @@ -2223,6 +2226,18 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * ds4_report = &bt->common; num_touch_reports = bt->num_touch_reports; touch_reports = bt->touch_reports; + } else if (hdev->bus == BUS_BLUETOOTH && + report->id == DS4_INPUT_REPORT_BT_MINIMAL && + size == DS4_INPUT_REPORT_BT_MINIMAL_SIZE) { + /* Some third-party pads never switch to the full 0x11 report. + * The short 0x01 report is 10 bytes long: + * u8 report_id == 0x01 + * u8 first_bytes_of_full_report[9] + * So let's reuse the full report parser, and stop it after + * parsing the buttons. + */ + ds4_report = (struct dualshock4_input_report_common *)&data[1]; + is_minimal = true; } else { hid_err(hdev, "Unhandled reportID=%d\n", report->id); return -1; @@ -2256,6 +2271,9 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * input_report_key(ds4->gamepad, BTN_MODE, ds4_report->buttons[2] & DS_BUTTONS2_PS_HOME); input_sync(ds4->gamepad); + if (is_minimal) + return 0; + /* Parse and calibrate gyroscope data. */ for (i = 0; i < ARRAY_SIZE(ds4_report->gyro); i++) { int raw_data = (short)le16_to_cpu(ds4_report->gyro[i]); -- cgit v1.2.3 From 8f607e007e8127627680e2e5e2cd70da76fb45b1 Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Thu, 8 Feb 2024 01:36:47 +0900 Subject: HID: playstation: Simplify device type ID Distinguish PS4/PS5 type controllers using .driver_data in MODULE_DEVICE_TABLE rather than by VID/PID. This allows adding compatible controllers with different VID/PID. Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 6b0f25688657..edc46fc02e9a 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -27,6 +27,11 @@ static DEFINE_IDA(ps_player_id_allocator); #define HID_PLAYSTATION_VERSION_PATCH 0x8000 +enum PS_TYPE { + PS_TYPE_PS4_DUALSHOCK4, + PS_TYPE_PS5_DUALSENSE, +}; + /* Base class for playstation devices. */ struct ps_device { struct list_head list; @@ -2687,17 +2692,14 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop; } - if (hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER || - hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 || - hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) { + if (id->driver_data == PS_TYPE_PS4_DUALSHOCK4) { dev = dualshock4_create(hdev); if (IS_ERR(dev)) { hid_err(hdev, "Failed to create dualshock4.\n"); ret = PTR_ERR(dev); goto err_close; } - } else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER || - hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) { + } else if (id->driver_data == PS_TYPE_PS5_DUALSENSE) { dev = dualsense_create(hdev); if (IS_ERR(dev)) { hid_err(hdev, "Failed to create dualsense.\n"); @@ -2731,16 +2733,26 @@ static void ps_remove(struct hid_device *hdev) static const struct hid_device_id ps_devices[] = { /* Sony DualShock 4 controllers for PS4 */ - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), + .driver_data = PS_TYPE_PS4_DUALSHOCK4 }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), + .driver_data = PS_TYPE_PS4_DUALSHOCK4 }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), + .driver_data = PS_TYPE_PS4_DUALSHOCK4 }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), + .driver_data = PS_TYPE_PS4_DUALSHOCK4 }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE), + .driver_data = PS_TYPE_PS4_DUALSHOCK4 }, + /* Sony DualSense controllers for PS5 */ - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER), + .driver_data = PS_TYPE_PS5_DUALSENSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER), + .driver_data = PS_TYPE_PS5_DUALSENSE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2), + .driver_data = PS_TYPE_PS5_DUALSENSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2), + .driver_data = PS_TYPE_PS5_DUALSENSE }, { } }; MODULE_DEVICE_TABLE(hid, ps_devices); -- cgit v1.2.3 From 4171954f56fb6da8cc8ceebf54b78b874278a198 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 15 Mar 2024 15:44:38 +0100 Subject: HID: bpf/dispatch: regroup kfuncs definitions No code change, just move down the hid_bpf_get_data() kfunc definition so we have only one block of __bpf_kfunc_start/end_defs() Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-1-079c282469d3@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 80 ++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index e630caf644e8..52abb27426f4 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -143,48 +143,6 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s } EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); -/* Disables missing prototype warnings */ -__bpf_kfunc_start_defs(); - -/** - * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx - * - * @ctx: The HID-BPF context - * @offset: The offset within the memory - * @rdwr_buf_size: the const size of the buffer - * - * @returns %NULL on error, an %__u8 memory pointer on success - */ -__bpf_kfunc __u8 * -hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size) -{ - struct hid_bpf_ctx_kern *ctx_kern; - - if (!ctx) - return NULL; - - ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); - - if (rdwr_buf_size + offset > ctx->allocated_size) - return NULL; - - return ctx_kern->data + offset; -} -__bpf_kfunc_end_defs(); - -/* - * The following set contains all functions we agree BPF programs - * can use. - */ -BTF_KFUNCS_START(hid_bpf_kfunc_ids) -BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL) -BTF_KFUNCS_END(hid_bpf_kfunc_ids) - -static const struct btf_kfunc_id_set hid_bpf_kfunc_set = { - .owner = THIS_MODULE, - .set = &hid_bpf_kfunc_ids, -}; - static int device_match_id(struct device *dev, const void *id) { struct hid_device *hdev = to_hid_device(dev); @@ -281,6 +239,31 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct b /* Disables missing prototype warnings */ __bpf_kfunc_start_defs(); +/** + * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx + * + * @ctx: The HID-BPF context + * @offset: The offset within the memory + * @rdwr_buf_size: the const size of the buffer + * + * @returns %NULL on error, an %__u8 memory pointer on success + */ +__bpf_kfunc __u8 * +hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size) +{ + struct hid_bpf_ctx_kern *ctx_kern; + + if (!ctx) + return NULL; + + ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); + + if (rdwr_buf_size + offset > ctx->allocated_size) + return NULL; + + return ctx_kern->data + offset; +} + /** * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device * @@ -474,6 +457,19 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, } __bpf_kfunc_end_defs(); +/* + * The following set contains all functions we agree BPF programs + * can use. + */ +BTF_KFUNCS_START(hid_bpf_kfunc_ids) +BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL) +BTF_KFUNCS_END(hid_bpf_kfunc_ids) + +static const struct btf_kfunc_id_set hid_bpf_kfunc_set = { + .owner = THIS_MODULE, + .set = &hid_bpf_kfunc_ids, +}; + /* our HID-BPF entrypoints */ BTF_SET8_START(hid_bpf_fmodret_ids) BTF_ID_FLAGS(func, hid_bpf_device_event) -- cgit v1.2.3 From 5599f80196612efde96dbe6ef18f6ecc0cb4ba19 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 15 Mar 2024 15:44:39 +0100 Subject: HID: bpf: export hid_hw_output_report as a BPF kfunc We currently only export hid_hw_raw_request() as a BPF kfunc. However, some devices require an explicit write on the Output Report instead of the use of the control channel. So also export hid_hw_output_report to BPF Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-2-079c282469d3@kernel.org Signed-off-by: Benjamin Tissoires --- Documentation/hid/hid-bpf.rst | 2 +- drivers/hid/bpf/hid_bpf_dispatch.c | 112 +++++++++++++++++++++++++++---------- drivers/hid/hid-core.c | 1 + include/linux/hid_bpf.h | 1 + 4 files changed, 86 insertions(+), 30 deletions(-) (limited to 'drivers/hid') diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst index 4fad83a6ebc3..a575004d9025 100644 --- a/Documentation/hid/hid-bpf.rst +++ b/Documentation/hid/hid-bpf.rst @@ -179,7 +179,7 @@ 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_allocate_context hid_bpf_release_context + :functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_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 52abb27426f4..0ccd7cdd29d8 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -376,6 +376,46 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx) put_device(&hid->dev); } +static int +__hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, + enum hid_report_type rtype) +{ + struct hid_report_enum *report_enum; + struct hid_report *report; + struct hid_device *hdev; + u32 report_len; + + /* check arguments */ + if (!ctx || !hid_bpf_ops || !buf) + return -EINVAL; + + switch (rtype) { + case HID_INPUT_REPORT: + case HID_OUTPUT_REPORT: + case HID_FEATURE_REPORT: + break; + default: + return -EINVAL; + } + + if (*buf__sz < 1) + return -EINVAL; + + hdev = (struct hid_device *)ctx->hid; /* discard const */ + + report_enum = hdev->report_enum + rtype; + report = hid_bpf_ops->hid_get_report(report_enum, buf); + if (!report) + return -EINVAL; + + report_len = hid_report_len(report); + + if (*buf__sz > report_len) + *buf__sz = report_len; + + return 0; +} + /** * hid_bpf_hw_request - Communicate with a HID device * @@ -392,24 +432,14 @@ 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_device *hdev; - struct hid_report *report; - struct hid_report_enum *report_enum; + size_t size = buf__sz; u8 *dma_data; - u32 report_len; int ret; /* check arguments */ - if (!ctx || !hid_bpf_ops || !buf) - return -EINVAL; - - switch (rtype) { - case HID_INPUT_REPORT: - case HID_OUTPUT_REPORT: - case HID_FEATURE_REPORT: - break; - default: - return -EINVAL; - } + ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype); + if (ret) + return ret; switch (reqtype) { case HID_REQ_GET_REPORT: @@ -423,29 +453,16 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, return -EINVAL; } - if (buf__sz < 1) - return -EINVAL; - hdev = (struct hid_device *)ctx->hid; /* discard const */ - report_enum = hdev->report_enum + rtype; - report = hid_bpf_ops->hid_get_report(report_enum, buf); - if (!report) - return -EINVAL; - - report_len = hid_report_len(report); - - if (buf__sz > report_len) - buf__sz = report_len; - - dma_data = kmemdup(buf, buf__sz, GFP_KERNEL); + dma_data = kmemdup(buf, size, GFP_KERNEL); if (!dma_data) return -ENOMEM; ret = hid_bpf_ops->hid_hw_raw_request(hdev, dma_data[0], dma_data, - buf__sz, + size, rtype, reqtype); @@ -455,6 +472,42 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, kfree(dma_data); return ret; } + +/** + * hid_bpf_hw_output_report - Send an output report to a HID device + * + * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context() + * @buf: a %PTR_TO_MEM buffer + * @buf__sz: the size of the data to transfer + * + * Returns the number of bytes transferred on success, a negative error code otherwise. + */ +__bpf_kfunc int +hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) +{ + struct hid_device *hdev; + size_t size = buf__sz; + u8 *dma_data; + int ret; + + /* check arguments */ + ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT); + if (ret) + return ret; + + hdev = (struct hid_device *)ctx->hid; /* discard const */ + + dma_data = kmemdup(buf, size, GFP_KERNEL); + if (!dma_data) + return -ENOMEM; + + ret = hid_bpf_ops->hid_hw_output_report(hdev, + dma_data, + size); + + kfree(dma_data); + return ret; +} __bpf_kfunc_end_defs(); /* @@ -488,6 +541,7 @@ 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) +BTF_ID_FLAGS(func, hid_bpf_hw_output_report) BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index de7a477d6665..1243595890ba 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2974,6 +2974,7 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed); static struct hid_bpf_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, .owner = THIS_MODULE, .bus_type = &hid_bus_type, }; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 7118ac28d468..5c7ff93dc73e 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -103,6 +103,7 @@ struct hid_bpf_ops { 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); struct module *owner; const struct bus_type *bus_type; }; -- cgit v1.2.3 From 9be50ac30a83896a753ab9f64e941763bb7900be Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 15 Mar 2024 15:44:42 +0100 Subject: HID: bpf: allow to inject HID event from BPF It can be interesting to inject events from BPF as if the event were to come from the device. For example, some multitouch devices do not all the time send a proximity out event, and we might want to send it for the physical device. Compared to uhid, we can now inject events on any physical device, not just uhid virtual ones. Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-5-079c282469d3@kernel.org Signed-off-by: Benjamin Tissoires --- Documentation/hid/hid-bpf.rst | 2 +- drivers/hid/bpf/hid_bpf_dispatch.c | 29 +++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + include/linux/hid_bpf.h | 2 ++ 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/Documentation/hid/hid-bpf.rst b/Documentation/hid/hid-bpf.rst index a575004d9025..0765b3298ecf 100644 --- a/Documentation/hid/hid-bpf.rst +++ b/Documentation/hid/hid-bpf.rst @@ -179,7 +179,7 @@ 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_allocate_context hid_bpf_release_context + :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 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 0ccd7cdd29d8..83e5c73ce995 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -508,6 +508,34 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) kfree(dma_data); return ret; } + +/** + * hid_bpf_input_report - Inject a HID report in the kernel from a HID device + * + * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context() + * @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT) + * @buf: a %PTR_TO_MEM buffer + * @buf__sz: the size of the data to transfer + * + * Returns %0 on success, a negative error code otherwise. + */ +__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; + + /* check arguments */ + ret = __hid_bpf_hw_check_params(ctx, buf, &size, type); + if (ret) + return ret; + + hdev = (struct hid_device *)ctx->hid; /* discard const */ + + return hid_input_report(hdev, type, buf, size, 0); +} __bpf_kfunc_end_defs(); /* @@ -542,6 +570,7 @@ 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) BTF_ID_FLAGS(func, hid_bpf_hw_output_report) +BTF_ID_FLAGS(func, hid_bpf_input_report) BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1243595890ba..b1fa0378e8f4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2975,6 +2975,7 @@ static struct hid_bpf_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, .owner = THIS_MODULE, .bus_type = &hid_bus_type, }; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 5c7ff93dc73e..17b08f500098 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -104,6 +104,8 @@ struct hid_bpf_ops { 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); + int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, + u8 *data, u32 size, int interrupt); struct module *owner; const struct bus_type *bus_type; }; -- cgit v1.2.3 From 685dadafbde29dc3d6b7a13be284d684b06d4d4f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 15 Mar 2024 15:44:44 +0100 Subject: HID: bpf: allow to use bpf_timer_set_sleepable_cb() in tracing callbacks. Export the sleepable kfuncs we have on HID-BPF in tracing bpf programs, but with the condition of being used in a sleepable context. This allows to use the bpf_timer when used in a sleepable context through bpf_timer_set_sleepable_cb() and initiate work from a device event. Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-7-079c282469d3@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 83e5c73ce995..79ece3d1b9e2 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -544,6 +544,11 @@ __bpf_kfunc_end_defs(); */ BTF_KFUNCS_START(hid_bpf_kfunc_ids) BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL) +BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) +BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE) +BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE) +BTF_ID_FLAGS(func, hid_bpf_hw_output_report, KF_SLEEPABLE) +BTF_ID_FLAGS(func, hid_bpf_input_report, KF_SLEEPABLE) BTF_KFUNCS_END(hid_bpf_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_kfunc_set = { -- cgit v1.2.3 From b912cf042072e12e93faa874265b30cc0aa521b9 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 11 Apr 2024 09:05:56 +0200 Subject: HID: bpf: fix hid_bpf_input_report() when hid-core is not ready Reported by linux-next: After merging the hid tree, today's linux-next build (x86_64 allmodconfig) failed like this: x86_64-linux-gnu-ld: vmlinux.o: in function `hid_bpf_input_report': (.text+0x1c75181): undefined reference to `hid_input_report' Caused by commit 9be50ac30a83 ("HID: bpf: allow to inject HID event from BPF") I just forgot to put the indirection in place. Link: https://lore.kernel.org/linux-kernel/20240411105131.7830f966@canb.auug.org.au/ Fixes: 9be50ac30a83 ("HID: bpf: allow to inject HID event from BPF") Link: https://lore.kernel.org/r/20240411-fix-hid-bpf-v1-1-4ae913031a8c@kernel.org Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/hid_bpf_dispatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 79ece3d1b9e2..10289f44d0cc 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -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_input_report(hdev, type, buf, size, 0); + return hid_bpf_ops->hid_input_report(hdev, type, buf, size, 0); } __bpf_kfunc_end_defs(); -- cgit v1.2.3 From 7e642aef8937dda15ad95e42418d85e73c76b47d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sun, 7 Apr 2024 10:28:04 +0800 Subject: HID: winwing: Remove unused variable 'minor' Variable minor is not effectively used, so delete it. drivers/hid/hid-winwing.c:123:15: warning: variable 'minor' set but not used. Fixes: 266c990debad2 ("HID: Add WinWing Orion2 throttle support") Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8705 Signed-off-by: Jiapeng Chong Signed-off-by: Jiri Kosina --- drivers/hid/hid-winwing.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c index d895c82a541d..0e224d1a6466 100644 --- a/drivers/hid/hid-winwing.c +++ b/drivers/hid/hid-winwing.c @@ -120,7 +120,6 @@ static int winwing_init_led(struct hid_device *hdev, static int winwing_probe(struct hid_device *hdev, const struct hid_device_id *id) { - unsigned int minor; int ret; ret = hid_parse(hdev); @@ -135,8 +134,6 @@ static int winwing_probe(struct hid_device *hdev, return ret; } - minor = ((struct hidraw *) hdev->hidraw)->minor; - return 0; } -- cgit v1.2.3 From f6e0f53a48809184c6d79177d1435fbff6b672c0 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sun, 7 Apr 2024 10:11:00 +0800 Subject: HID: nintendo: Remove unused function The function are defined in the hid-nintendo.c file, but not called elsewhere, so delete the unused function. drivers/hid/hid-nintendo.c:697:20: warning: unused function 'joycon_device_has_usb'. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=8704 Signed-off-by: Jiapeng Chong Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index e311b092e758..b0d6c6db522d 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -694,15 +694,6 @@ static inline bool joycon_device_is_n64con(struct joycon_ctlr *ctlr) return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON; } -static inline bool joycon_device_has_usb(struct joycon_ctlr *ctlr) -{ - return joycon_device_is_procon(ctlr) || - joycon_device_is_chrggrip(ctlr) || - joycon_device_is_snescon(ctlr) || - joycon_device_is_gencon(ctlr) || - joycon_device_is_n64con(ctlr); -} - /* * Controller type helpers * -- cgit v1.2.3 From 4e124ed0da2939dcd27849a3d6f41fbc537a20be Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 28 Mar 2024 12:22:13 +0000 Subject: HID: sony: remove redundant assignment The variable ret is being assigned a value that is never read afterwards. The assignment is redundant and can be removed. Cleans up clang scan build warning: drivers/hid/hid-sony.c:2020:3: warning: Value stored to 'ret' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ebc0aa4e4345..1d37b39e1171 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2016,8 +2016,6 @@ static int sony_input_configured(struct hid_device *hdev, } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); - } else { - ret = 0; } if (sc->quirks & SONY_LED_SUPPORT) { -- cgit v1.2.3 From 45bf5edd0f9612f41be405b583af886168174e8b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 14 Apr 2024 12:03:11 +0200 Subject: HID: sony: Remove usage of the deprecated ida_simple_xx() API ida_alloc() and ida_free() should be preferred to the deprecated ida_simple_get() and ida_simple_remove(). This is less verbose. Signed-off-by: Christophe JAILLET Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 1d37b39e1171..5a07a91a89ae 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1844,8 +1844,7 @@ static int sony_set_device_id(struct sony_sc *sc) * All others are set to -1. */ if (sc->quirks & SIXAXIS_CONTROLLER) { - ret = ida_simple_get(&sony_device_id_allocator, 0, 0, - GFP_KERNEL); + ret = ida_alloc(&sony_device_id_allocator, GFP_KERNEL); if (ret < 0) { sc->device_id = -1; return ret; @@ -1861,7 +1860,7 @@ static int sony_set_device_id(struct sony_sc *sc) static void sony_release_device_id(struct sony_sc *sc) { if (sc->device_id >= 0) { - ida_simple_remove(&sony_device_id_allocator, sc->device_id); + ida_free(&sony_device_id_allocator, sc->device_id); sc->device_id = -1; } } -- cgit v1.2.3 From 3347e1654f24dbbd357ea4e3c0d8dcc12d8586c7 Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Sat, 20 Apr 2024 12:34:18 +0000 Subject: HID: hid-steam: Add Deck IMU support The Deck's controller features an accelerometer and gyroscope which send their measurement values by default in the main HID input report. Expose both sensors to userspace through a separate evdev node as it is done by the hid-nintendo and hid-playstation drivers. Signed-off-by: Max Maisel Reviewed-by: Vicki Pfau Signed-off-by: Jiri Kosina --- drivers/hid/hid-steam.c | 155 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 147 insertions(+), 8 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index b08a5ab58528..f166188c21ec 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -66,6 +66,14 @@ static LIST_HEAD(steam_devices); #define STEAM_DECK_TRIGGER_RESOLUTION 5461 /* Joystick runs are about 5 mm and 32768 units */ #define STEAM_DECK_JOYSTICK_RESOLUTION 6553 +/* Accelerometer has 16 bit resolution and a range of +/- 2g */ +#define STEAM_DECK_ACCEL_RES_PER_G 16384 +#define STEAM_DECK_ACCEL_RANGE 32768 +#define STEAM_DECK_ACCEL_FUZZ 32 +/* Gyroscope has 16 bit resolution and a range of +/- 2000 dps */ +#define STEAM_DECK_GYRO_RES_PER_DPS 16 +#define STEAM_DECK_GYRO_RANGE 32768 +#define STEAM_DECK_GYRO_FUZZ 1 #define STEAM_PAD_FUZZ 256 @@ -288,6 +296,7 @@ struct steam_device { struct mutex report_mutex; unsigned long client_opened; struct input_dev __rcu *input; + struct input_dev __rcu *sensors; unsigned long quirks; struct work_struct work_connect; bool connected; @@ -302,6 +311,7 @@ struct steam_device { struct work_struct rumble_work; u16 rumble_left; u16 rumble_right; + unsigned int sensor_timestamp_us; }; static int steam_recv_report(struct steam_device *steam, @@ -825,6 +835,74 @@ input_register_fail: return ret; } +static int steam_sensors_register(struct steam_device *steam) +{ + struct hid_device *hdev = steam->hdev; + struct input_dev *sensors; + int ret; + + if (!(steam->quirks & STEAM_QUIRK_DECK)) + return 0; + + rcu_read_lock(); + sensors = rcu_dereference(steam->sensors); + rcu_read_unlock(); + if (sensors) { + dbg_hid("%s: already connected\n", __func__); + return 0; + } + + sensors = input_allocate_device(); + if (!sensors) + return -ENOMEM; + + input_set_drvdata(sensors, steam); + sensors->dev.parent = &hdev->dev; + + sensors->name = "Steam Deck Motion Sensors"; + sensors->phys = hdev->phys; + sensors->uniq = steam->serial_no; + sensors->id.bustype = hdev->bus; + sensors->id.vendor = hdev->vendor; + sensors->id.product = hdev->product; + sensors->id.version = hdev->version; + + __set_bit(INPUT_PROP_ACCELEROMETER, sensors->propbit); + __set_bit(EV_MSC, sensors->evbit); + __set_bit(MSC_TIMESTAMP, sensors->mscbit); + + input_set_abs_params(sensors, ABS_X, -STEAM_DECK_ACCEL_RANGE, + STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); + input_set_abs_params(sensors, ABS_Y, -STEAM_DECK_ACCEL_RANGE, + STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); + input_set_abs_params(sensors, ABS_Z, -STEAM_DECK_ACCEL_RANGE, + STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); + input_abs_set_res(sensors, ABS_X, STEAM_DECK_ACCEL_RES_PER_G); + input_abs_set_res(sensors, ABS_Y, STEAM_DECK_ACCEL_RES_PER_G); + input_abs_set_res(sensors, ABS_Z, STEAM_DECK_ACCEL_RES_PER_G); + + input_set_abs_params(sensors, ABS_RX, -STEAM_DECK_GYRO_RANGE, + STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); + input_set_abs_params(sensors, ABS_RY, -STEAM_DECK_GYRO_RANGE, + STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); + input_set_abs_params(sensors, ABS_RZ, -STEAM_DECK_GYRO_RANGE, + STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); + input_abs_set_res(sensors, ABS_RX, STEAM_DECK_GYRO_RES_PER_DPS); + input_abs_set_res(sensors, ABS_RY, STEAM_DECK_GYRO_RES_PER_DPS); + input_abs_set_res(sensors, ABS_RZ, STEAM_DECK_GYRO_RES_PER_DPS); + + ret = input_register_device(sensors); + if (ret) + goto sensors_register_fail; + + rcu_assign_pointer(steam->sensors, sensors); + return 0; + +sensors_register_fail: + input_free_device(sensors); + return ret; +} + static void steam_input_unregister(struct steam_device *steam) { struct input_dev *input; @@ -838,6 +916,24 @@ static void steam_input_unregister(struct steam_device *steam) input_unregister_device(input); } +static void steam_sensors_unregister(struct steam_device *steam) +{ + struct input_dev *sensors; + + if (!(steam->quirks & STEAM_QUIRK_DECK)) + return; + + rcu_read_lock(); + sensors = rcu_dereference(steam->sensors); + rcu_read_unlock(); + + if (!sensors) + return; + RCU_INIT_POINTER(steam->sensors, NULL); + synchronize_rcu(); + input_unregister_device(sensors); +} + static void steam_battery_unregister(struct steam_device *steam) { struct power_supply *battery; @@ -890,18 +986,28 @@ static int steam_register(struct steam_device *steam) spin_lock_irqsave(&steam->lock, flags); client_opened = steam->client_opened; spin_unlock_irqrestore(&steam->lock, flags); + if (!client_opened) { steam_set_lizard_mode(steam, lizard_mode); ret = steam_input_register(steam); - } else - ret = 0; + if (ret != 0) + goto steam_register_input_fail; + ret = steam_sensors_register(steam); + if (ret != 0) + goto steam_register_sensors_fail; + } + return 0; +steam_register_sensors_fail: + steam_input_unregister(steam); +steam_register_input_fail: return ret; } static void steam_unregister(struct steam_device *steam) { steam_battery_unregister(steam); + steam_sensors_unregister(steam); steam_input_unregister(steam); if (steam->serial_no[0]) { hid_info(steam->hdev, "Steam Controller '%s' disconnected", @@ -1010,6 +1116,7 @@ static int steam_client_ll_open(struct hid_device *hdev) steam->client_opened++; spin_unlock_irqrestore(&steam->lock, flags); + steam_sensors_unregister(steam); steam_input_unregister(steam); return 0; @@ -1030,6 +1137,7 @@ static void steam_client_ll_close(struct hid_device *hdev) if (connected) { steam_set_lizard_mode(steam, lizard_mode); steam_input_register(steam); + steam_sensors_register(steam); } } @@ -1121,6 +1229,7 @@ static int steam_probe(struct hid_device *hdev, INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb); INIT_LIST_HEAD(&steam->list); INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); + steam->sensor_timestamp_us = 0; /* * With the real steam controller interface, do not connect hidraw. @@ -1380,12 +1489,12 @@ static void steam_do_input_event(struct steam_device *steam, * 18-19 | s16 | ABS_HAT0Y | left-pad Y value * 20-21 | s16 | ABS_HAT1X | right-pad X value * 22-23 | s16 | ABS_HAT1Y | right-pad Y value - * 24-25 | s16 | -- | accelerometer X value - * 26-27 | s16 | -- | accelerometer Y value - * 28-29 | s16 | -- | accelerometer Z value - * 30-31 | s16 | -- | gyro X value - * 32-33 | s16 | -- | gyro Y value - * 34-35 | s16 | -- | gyro Z value + * 24-25 | s16 | IMU ABS_X | accelerometer X value + * 26-27 | s16 | IMU ABS_Z | accelerometer Y value + * 28-29 | s16 | IMU ABS_Y | accelerometer Z value + * 30-31 | s16 | IMU ABS_RX | gyro X value + * 32-33 | s16 | IMU ABS_RZ | gyro Y value + * 34-35 | s16 | IMU ABS_RY | gyro Z value * 36-37 | s16 | -- | quaternion W value * 38-39 | s16 | -- | quaternion X value * 40-41 | s16 | -- | quaternion Y value @@ -1546,6 +1655,32 @@ static void steam_do_deck_input_event(struct steam_device *steam, input_sync(input); } +static void steam_do_deck_sensors_event(struct steam_device *steam, + struct input_dev *sensors, u8 *data) +{ + /* + * The deck input report is received every 4 ms on average, + * with a jitter of +/- 4 ms even though the USB descriptor claims + * that it uses 1 kHz. + * Since the HID report does not include a sensor timestamp, + * use a fixed increment here. + */ + steam->sensor_timestamp_us += 4000; + + if (!steam->gamepad_mode) + return; + + input_event(sensors, EV_MSC, MSC_TIMESTAMP, steam->sensor_timestamp_us); + input_report_abs(sensors, ABS_X, steam_le16(data + 24)); + input_report_abs(sensors, ABS_Z, -steam_le16(data + 26)); + input_report_abs(sensors, ABS_Y, steam_le16(data + 28)); + input_report_abs(sensors, ABS_RX, steam_le16(data + 30)); + input_report_abs(sensors, ABS_RZ, -steam_le16(data + 32)); + input_report_abs(sensors, ABS_RY, steam_le16(data + 34)); + + input_sync(sensors); +} + /* * The size for this message payload is 11. * The known values are: @@ -1583,6 +1718,7 @@ static int steam_raw_event(struct hid_device *hdev, { struct steam_device *steam = hid_get_drvdata(hdev); struct input_dev *input; + struct input_dev *sensors; struct power_supply *battery; if (!steam) @@ -1628,6 +1764,9 @@ static int steam_raw_event(struct hid_device *hdev, input = rcu_dereference(steam->input); if (likely(input)) steam_do_deck_input_event(steam, input, data); + sensors = rcu_dereference(steam->sensors); + if (likely(sensors)) + steam_do_deck_sensors_event(steam, sensors, data); rcu_read_unlock(); break; case ID_CONTROLLER_WIRELESS: -- cgit v1.2.3 From dd2c345a94cfa3873cc20db87387ee509c345c1b Mon Sep 17 00:00:00 2001 From: Sean O'Brien Date: Mon, 29 Apr 2024 18:08:05 +0000 Subject: HID: Add quirk for Logitech Casa touchpad This device sometimes doesn't send touch release signals when moving from >=4 fingers to <4 fingers. Using MT_QUIRK_NOT_SEEN_MEANS_UP instead of MT_QUIRK_ALWAYS_VALID makes sure that no touches become stuck. MT_QUIRK_FORCE_MULTI_INPUT is not necessary for this device, but does no harm. Signed-off-by: Sean O'Brien Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8376fb5e2d0b..68b0f39deaa9 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -823,6 +823,7 @@ #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e #define USB_DEVICE_ID_LOGITECH_T651 0xb00c #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 +#define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 #define USB_DEVICE_ID_LOGITECH_C007 0xc007 #define USB_DEVICE_ID_LOGITECH_C077 0xc077 #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 04a014cd2a2f..56fc78841f24 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -2081,6 +2081,12 @@ static const struct hid_device_id mt_devices[] = { USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) }, + /* Logitech devices */ + { .driver_data = MT_CLS_NSMU, + HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_LOGITECH, + USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD) }, + /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, MT_USB_DEVICE(USB_VENDOR_ID_ASUS, -- cgit v1.2.3 From 815234a4e7ebd3fdcdd25224bd92db63b77849b2 Mon Sep 17 00:00:00 2001 From: Thomas Kuehne Date: Sat, 13 Apr 2024 12:20:51 +0000 Subject: HID: hid-debug: fix Moir -> Moire typo This adds the letter "e" to fix hid_usage_table' HorizontalMoir and VerticalMoir entries. Signed-off-by: ThomasKuehne <2562574+ThomasKuehne@users.noreply.github.com> Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index add353a17853..a62e71a5ccef 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -2361,8 +2361,8 @@ static const struct hid_usage_entry hid_usage_table[] = { { 0x82, 0x0048, "TopCornerDistortionBalance" }, { 0x82, 0x004a, "BottomCornerDistortionControl" }, { 0x82, 0x004c, "BottomCornerDistortionBalance" }, - { 0x82, 0x0056, "HorizontalMoir" }, - { 0x82, 0x0058, "VerticalMoir" }, + { 0x82, 0x0056, "HorizontalMoire" }, + { 0x82, 0x0058, "VerticalMoire" }, { 0x82, 0x005e, "InputLevelSelect" }, { 0x82, 0x0060, "InputSourceSelect" }, { 0x82, 0x006c, "RedVideoBlackLevel" }, -- cgit v1.2.3 From 132ea824930d485ab82c1635cb4b0b38db95eb80 Mon Sep 17 00:00:00 2001 From: Thomas Kuehne Date: Sat, 13 Apr 2024 12:23:30 +0000 Subject: HID: hid-debug: more informative output for EV_KEY Currently hid-debug's hid_resolv_event prints questions marks for all entries without explicit mapping information. This makes debugging unnecessarily complicated as multiple different keys may simply result in the same uninformative output. Some common event codes are deliberately not defined in input-event-codes.h. For example the 16th gamepad key. Instead, print the hexadecimal codes for all events without symbolic names. Signed-off-by: Thomas Kuehne Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a62e71a5ccef..28b458fc6972 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -3582,8 +3582,15 @@ static const char **names[EV_MAX + 1] = { static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) { - seq_printf(f, "%s.%s", events[type] ? events[type] : "?", - names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); + if (events[type]) + seq_printf(f, "%s.", events[type]); + else + seq_printf(f, "%02x.", type); + + if (names[type] && names[type][code]) + seq_printf(f, "%s", names[type][code]); + else + seq_printf(f, "%04x", code); } static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) -- cgit v1.2.3 From 311e435c9b918ee45ba2ed2791ea4d848f5b05e5 Mon Sep 17 00:00:00 2001 From: Thomas Kuehne Date: Sat, 13 Apr 2024 12:39:17 +0000 Subject: HID: hid-debug: add EV_FF and FF_STATUS mappings Currently hid-debug only output question marks for all force feedback related input mapping making debugging gamepads with force feedback a challenge. This adds the necessary mapping information to output EV_FF and FF_STATUS related information. Signed-off-by: Thomas Kuehne Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 28b458fc6972..87a961cae775 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -3572,12 +3572,38 @@ static const char *software[SW_CNT] = { [SW_MACHINE_COVER] = "MachineCover", }; +static const char *force[FF_CNT] = { + [FF_RUMBLE] = "FF_RUMBLE", + [FF_PERIODIC] = "FF_PERIODIC", + [FF_CONSTANT] = "FF_CONSTANT", + [FF_SPRING] = "FF_SPRING", + [FF_FRICTION] = "FF_FRICTION", + [FF_DAMPER] = "FF_DAMPER", + [FF_INERTIA] = "FF_INERTIA", + [FF_RAMP] = "FF_RAMP", + [FF_SQUARE] = "FF_SQUARE", + [FF_TRIANGLE] = "FF_TRIANGLE", + [FF_SINE] = "FF_SINE", + [FF_SAW_UP] = "FF_SAW_UP", + [FF_SAW_DOWN] = "FF_SAW_DOWN", + [FF_CUSTOM] = "FF_CUSTOM", + [FF_GAIN] = "FF_GAIN", + [FF_AUTOCENTER] = "FF_AUTOCENTER", + [FF_MAX] = "FF_MAX", +}; + +static const char *force_status[FF_STATUS_MAX + 1] = { + [FF_STATUS_STOPPED] = "FF_STATUS_STOPPED", + [FF_STATUS_PLAYING] = "FF_STATUS_PLAYING", +}; + static const char **names[EV_MAX + 1] = { [EV_SYN] = syncs, [EV_KEY] = keys, [EV_REL] = relatives, [EV_ABS] = absolutes, [EV_MSC] = misc, [EV_LED] = leds, [EV_SND] = sounds, [EV_REP] = repeats, - [EV_SW] = software, + [EV_SW] = software, [EV_FF] = force, + [EV_FF_STATUS] = force_status, }; static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) -- cgit v1.2.3 From b88ee22809eb7fc9e196c24f43077cd7783eed9b Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 24 Apr 2024 13:31:30 +0200 Subject: HID: logitech: add a few Logitech HID++ device IDs Adds a few recognized Logitech HID++ capable mice over USB and Bluetooth Signed-off-by: Allan Sandfeld Jensen Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index d2f3f234f29d..b81d5bcc76a7 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4603,6 +4603,12 @@ static const struct hid_device_id hidpp_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) }, { /* Logitech G903 Gaming Mouse over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC086) }, + { /* Logitech G Pro Gaming Mouse over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) }, + { /* MX Vertical over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08A) }, + { /* Logitech G703 Hero Gaming Mouse over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC090) }, { /* Logitech G903 Hero Gaming Mouse over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC091) }, { /* Logitech G915 TKL Keyboard over USB */ @@ -4613,8 +4619,6 @@ static const struct hid_device_id hidpp_devices[] = { { /* Logitech G923 Wheel (Xbox version) over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL), .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS }, - { /* Logitech G Pro Gaming Mouse over USB */ - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) }, { /* Logitech G Pro X Superlight Gaming Mouse over USB */ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) }, { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */ @@ -4641,9 +4645,13 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012) }, { /* M720 Triathlon mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb015) }, + { /* MX Master 2S mouse over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb019) }, { /* MX Ergo trackball over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) }, + { /* MX Vertical mouse over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb020) }, { /* Signature M650 over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) }, { /* MX Master 3 mouse over Bluetooth */ @@ -4652,6 +4660,8 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb025) }, { /* MX Master 3S mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, + { /* MX Anywhere 3SB mouse over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, {} }; -- cgit v1.2.3 From 59d2f5b7392e988a391e6924e177c1a68d50223d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 16 Apr 2024 21:03:59 +1200 Subject: HID: asus: fix more n-key report descriptors if n-key quirked Adjusts the report descriptor for N-Key devices to make the output count 0x01 which completely avoids the need for a block of filtering. Signed-off-by: Luke D. Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 51 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 78cdfb8b9a7a..d6d8a028623a 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -335,36 +335,20 @@ static int asus_raw_event(struct hid_device *hdev, if (drvdata->quirks & QUIRK_MEDION_E1239T) return asus_e1239t_event(drvdata, data, size); - if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) { + /* + * Skip these report ID, the device emits a continuous stream associated + * with the AURA mode it is in which looks like an 'echo'. + */ + if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2) + return -1; + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { /* - * Skip these report ID, the device emits a continuous stream associated - * with the AURA mode it is in which looks like an 'echo'. + * G713 and G733 send these codes on some keypresses, depending on + * the key pressed it can trigger a shutdown event if not caught. */ - if (report->id == FEATURE_KBD_LED_REPORT_ID1 || - report->id == FEATURE_KBD_LED_REPORT_ID2) { + if (data[0] == 0x02 && data[1] == 0x30) { return -1; - /* Additional report filtering */ - } else if (report->id == FEATURE_KBD_REPORT_ID) { - /* - * G14 and G15 send these codes on some keypresses with no - * discernable reason for doing so. We'll filter them out to avoid - * unmapped warning messages later. - */ - if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 || - data[1] == 0x8a || data[1] == 0x9e) { - return -1; - } } - if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { - /* - * G713 and G733 send these codes on some keypresses, depending on - * the key pressed it can trigger a shutdown event if not caught. - */ - if(data[0] == 0x02 && data[1] == 0x30) { - return -1; - } - } - } if (drvdata->quirks & QUIRK_ROG_CLAYMORE_II_KEYBOARD) { @@ -1250,6 +1234,19 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[205] = 0x01; } + /* match many more n-key devices */ + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + for (int i = 0; i < *rsize + 1; i++) { + /* offset to the count from 0x5a report part always 14 */ + if (rdesc[i] == 0x85 && rdesc[i + 1] == 0x5a && + rdesc[i + 14] == 0x95 && rdesc[i + 15] == 0x05) { + hid_info(hdev, "Fixing up Asus N-Key report descriptor\n"); + rdesc[i + 15] = 0x01; + break; + } + } + } + return rdesc; } @@ -1319,4 +1316,4 @@ static struct hid_driver asus_driver = { }; module_hid_driver(asus_driver); -MODULE_LICENSE("GPL"); \ No newline at end of file +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2c82a7b20f7b7afcfacdde230e1233efc9c881e5 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 16 Apr 2024 21:04:00 +1200 Subject: HID: asus: make asus_kbd_init() generic, remove rog_nkey_led_init() Some of the n-key stuff is old and outdated, so make asus_kbd_init() generic to use with other report ID and remove rog_nkey_led_init(). Signed-off-by: Luke D. Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 70 +++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 52 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d6d8a028623a..18062f9804fb 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -386,9 +386,9 @@ static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t bu return ret; } -static int asus_kbd_init(struct hid_device *hdev) +static int asus_kbd_init(struct hid_device *hdev, u8 report_id) { - const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, + const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; int ret; @@ -400,9 +400,10 @@ static int asus_kbd_init(struct hid_device *hdev) } static int asus_kbd_get_functions(struct hid_device *hdev, - unsigned char *kbd_func) + unsigned char *kbd_func, + u8 report_id) { - const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; + const u8 buf[] = { report_id, 0x05, 0x20, 0x31, 0x00, 0x08 }; u8 *readbuf; int ret; @@ -431,51 +432,6 @@ static int asus_kbd_get_functions(struct hid_device *hdev, return ret; } -static int rog_nkey_led_init(struct hid_device *hdev) -{ - const u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; - u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, - 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; - u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, - 0x05, 0x20, 0x31, 0x00, 0x08 }; - int ret; - - hid_info(hdev, "Asus initialise N-KEY Device"); - /* The first message is an init start */ - ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start)); - if (ret < 0) { - hid_warn(hdev, "Asus failed to send init start command: %d\n", ret); - return ret; - } - /* Followed by a string */ - ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); - if (ret < 0) { - hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret); - return ret; - } - /* Followed by a string */ - ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); - if (ret < 0) { - hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret); - return ret; - } - - /* begin second report ID with same data */ - buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2; - buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2; - - ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); - if (ret < 0) { - hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret); - return ret; - } - ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); - if (ret < 0) - hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret); - - return ret; -} - static void asus_schedule_work(struct asus_kbd_leds *led) { unsigned long flags; @@ -558,17 +514,27 @@ static int asus_kbd_register_leds(struct hid_device *hdev) int ret; if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { - ret = rog_nkey_led_init(hdev); + /* Initialize keyboard */ + ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); + if (ret < 0) + return ret; + + /* The LED endpoint is initialised in two HID */ + ret = asus_kbd_init(hdev, FEATURE_KBD_LED_REPORT_ID1); + if (ret < 0) + return ret; + + ret = asus_kbd_init(hdev, FEATURE_KBD_LED_REPORT_ID2); if (ret < 0) return ret; } else { /* Initialize keyboard */ - ret = asus_kbd_init(hdev); + ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); if (ret < 0) return ret; /* Get keyboard functions */ - ret = asus_kbd_get_functions(hdev, &kbd_func); + ret = asus_kbd_get_functions(hdev, &kbd_func, FEATURE_KBD_REPORT_ID); if (ret < 0) return ret; -- cgit v1.2.3 From 08b50c6b0b0940a304b481346cc187d489c6a751 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 16 Apr 2024 21:04:01 +1200 Subject: HID: asus: add ROG Ally N-Key ID and keycodes A handful of buttons on the ROG Ally are not actually part of the xpad device and are instead keyboard keys (a typical use of the MCU that asus uses). We attach a group of F key codes which aren't used much and which the handheld community has already accepted as defaults here. Signed-off-by: Luke D. Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 8 +++++++- drivers/hid/hid-ids.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 18062f9804fb..61820f7a6b25 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -847,7 +847,10 @@ static int asus_input_mapping(struct hid_device *hdev, case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */ case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */ case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */ - + case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally left back */ + case 0xa6: asus_map_key_clear(KEY_F16); break; /* ROG Ally QAM button */ + case 0xa7: asus_map_key_clear(KEY_F17); break; /* ROG Ally ROG long-press */ + case 0xa8: asus_map_key_clear(KEY_F18); break; /* ROG Ally ROG long-press-release */ default: /* ASUS lazily declares 256 usages, ignore the rest, @@ -1239,6 +1242,9 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), QUIRK_ROG_CLAYMORE_II_KEYBOARD }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8376fb5e2d0b..f1e508a7ef06 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -208,6 +208,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 +#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 -- cgit v1.2.3 From e901f10adb1f387fff1082297065a0da0191b83d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Tue, 16 Apr 2024 21:04:02 +1200 Subject: HID: asus: add ROG Z13 lightbar Add init of the lightbar which is a small panel on the back of the ASUS ROG Z13 and uses the same MCU as keyboards. Signed-off-by: Luke D. Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 3 +++ drivers/hid/hid-ids.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 61820f7a6b25..02de2bf4f790 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -1242,6 +1242,9 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f1e508a7ef06..94501dbdd463 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -208,6 +208,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 +#define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 -- cgit v1.2.3 From ab5ec06a7070840bb64a125fe6e5b0ddcb36346c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 30 Apr 2024 01:33:14 +0200 Subject: HID: i2c-hid: Retry address probe after delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some STM microcontrollers need 400µs after rising clock edge in order to come out of their deep sleep state. This in turn means that our address probe will fail as the device is not ready to service it. Retry the probe once after a delay to see if the device came alive, otherwise treat the device as missing. Link: https://lore.kernel.org/all/20240405102436.3479210-1-lma@chromium.org/#t Co-developed-by: Radoslaw Biernacki Co-developed-by: Lukasz Majczak Signed-off-by: Kenny Levinsen Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 2df1ab3c31cc..39ed58a8a04c 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -164,6 +164,24 @@ static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) return quirks; } +static int i2c_hid_probe_address(struct i2c_hid *ihid) +{ + int ret; + + /* + * Some STM-based devices need 400µs after a rising clock edge to wake + * from deep sleep, in which case the first read will fail. Try after a + * short sleep to see if the device came alive on the bus. Certain + * Weida Tech devices also need this. + */ + ret = i2c_smbus_read_byte(ihid->client); + if (ret < 0) { + usleep_range(400, 500); + ret = i2c_smbus_read_byte(ihid->client); + } + return ret < 0 ? ret : 0; +} + static int i2c_hid_xfer(struct i2c_hid *ihid, u8 *send_buf, int send_len, u8 *recv_buf, int recv_len) { @@ -1014,8 +1032,7 @@ static int __i2c_hid_core_probe(struct i2c_hid *ihid) struct hid_device *hid = ihid->hid; int ret; - /* Make sure there is something at this address */ - ret = i2c_smbus_read_byte(client); + ret = i2c_hid_probe_address(ihid); if (ret < 0) { i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret); return -ENXIO; -- cgit v1.2.3 From 7d6f065de37c31c37e56611efd41260c66c868ca Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 30 Apr 2024 01:33:15 +0200 Subject: HID: i2c-hid: Use address probe to wake on resume Certain devices, both from STM and Weida Tech, need to be woken up after having entered a deeper sleep state. The relevant places to wake up such device is during our initial HID probe, and after resuming. A retry for power commands was previously added to i2c_hid_set_power to wake up Weida Tech devices, but lacked sufficient sleep for STM devices. Replace the power command retry with the same address probe we using during our initial HID probe. Signed-off-by: Kenny Levinsen Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 39ed58a8a04c..13666c27b02e 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -408,19 +408,6 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) i2c_hid_dbg(ihid, "%s\n", __func__); - /* - * Some devices require to send a command to wakeup before power on. - * The call will get a return value (EREMOTEIO) but device will be - * triggered and activated. After that, it goes like a normal device. - */ - if (power_state == I2C_HID_PWR_ON) { - ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON); - - /* Device was already activated */ - if (!ret) - goto set_pwr_exit; - } - ret = i2c_hid_set_power_command(ihid, power_state); if (ret) dev_err(&ihid->client->dev, @@ -999,6 +986,14 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid) enable_irq(client->irq); + /* Make sure the device is awake on the bus */ + ret = i2c_hid_probe_address(ihid); + if (ret < 0) { + dev_err(&client->dev, "nothing at address after resume: %d\n", + ret); + return -ENXIO; + } + /* Instead of resetting device, simply powers the device on. This * solves "incomplete reports" on Raydium devices 2386:3118 and * 2386:4B33 and fixes various SIS touchscreens no longer sending -- cgit v1.2.3 From 947992c7fa9e0e7adf2451e7b7a88ce550248794 Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Sun, 5 May 2024 01:55:32 +0900 Subject: HID: playstation: DS4: Fix calibration workaround for clone devices The logic in dualshock4_get_calibration_data() used uninitialised data in case of a failed kzalloc() for the transfer buffer. The solution is to group all business logic and all sanity checks together, and jump only to the latter in case of an error. While we're at it, factor out the axes' labelling, since it must happen either way for input_report_abs() to succeed later on. Thanks to Dan Carpenter for the Smatch static checker warning. Fixes: a48a7cd85f55 ("HID: playstation: DS4: Don't fail on calibration data request") Signed-off-by: Max Staudt Signed-off-by: Jiri Kosina --- drivers/hid/hid-playstation.c | 52 +++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index edc46fc02e9a..e7c309cfe3a0 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -1787,7 +1787,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); if (!buf) { ret = -ENOMEM; - goto no_buffer_tail_check; + goto transfer_failed; } /* We should normally receive the feature report data we asked @@ -1807,6 +1807,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); ret = -EILSEQ; + goto transfer_failed; } else { break; } @@ -1815,17 +1816,19 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, GFP_KERNEL); if (!buf) { ret = -ENOMEM; - goto no_buffer_tail_check; + goto transfer_failed; } ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf, DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true); - if (ret) + if (ret) { hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); + goto transfer_failed; + } } - /* Parse buffer. If the transfer failed, this safely copies zeroes. */ + /* Transfer succeeded - parse the calibration data received. */ gyro_pitch_bias = get_unaligned_le16(&buf[1]); gyro_yaw_bias = get_unaligned_le16(&buf[3]); gyro_roll_bias = get_unaligned_le16(&buf[5]); @@ -1854,6 +1857,9 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) acc_z_plus = get_unaligned_le16(&buf[31]); acc_z_minus = get_unaligned_le16(&buf[33]); + /* Done parsing the buffer, so let's free it. */ + kfree(buf); + /* * Set gyroscope calibration and normalization parameters. * Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s. @@ -1877,26 +1883,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); - /* Done parsing the buffer, so let's free it. */ - kfree(buf); - -no_buffer_tail_check: - - /* - * Sanity check gyro calibration data. This is needed to prevent crashes - * during report handling of virtual, clone or broken devices not implementing - * calibration data properly. - */ - for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) { - if (ds4->gyro_calib_data[i].sens_denom == 0) { - hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", - ds4->gyro_calib_data[i].abs_code); - ds4->gyro_calib_data[i].bias = 0; - ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE; - ds4->gyro_calib_data[i].sens_denom = S16_MAX; - } - } - /* * Set accelerometer calibration and normalization parameters. * Data values will be normalized to 1/DS4_ACC_RES_PER_G g. @@ -1919,6 +1905,23 @@ no_buffer_tail_check: ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G; ds4->accel_calib_data[2].sens_denom = range_2g; +transfer_failed: + /* + * Sanity check gyro calibration data. This is needed to prevent crashes + * during report handling of virtual, clone or broken devices not implementing + * calibration data properly. + */ + for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) { + if (ds4->gyro_calib_data[i].sens_denom == 0) { + ds4->gyro_calib_data[i].abs_code = ABS_RX + i; + hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds4->gyro_calib_data[i].abs_code); + ds4->gyro_calib_data[i].bias = 0; + ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE; + ds4->gyro_calib_data[i].sens_denom = S16_MAX; + } + } + /* * Sanity check accelerometer calibration data. This is needed to prevent crashes * during report handling of virtual, clone or broken devices not implementing calibration @@ -1926,6 +1929,7 @@ no_buffer_tail_check: */ for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) { if (ds4->accel_calib_data[i].sens_denom == 0) { + ds4->accel_calib_data[i].abs_code = ABS_X + i; hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", ds4->accel_calib_data[i].abs_code); ds4->accel_calib_data[i].bias = 0; -- cgit v1.2.3 From 6b2a374adfa8b58e2da2ca07245c2774fd6ea9b4 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 6 May 2024 09:30:38 +0800 Subject: HID: intel-ish-hid: Add driver_data for specifying the firmware filename Introduces a new structure, ishtp_driver_data, to hold driver-specific data, including the firmware filename for different hardware variants of the Intel Integrated Sensor Hub (ISH). Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 18 +++++++++++++++++- drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index e79d72f7db2a..d487227085b2 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -23,6 +23,19 @@ #include "ishtp-dev.h" #include "hw-ish.h" +enum ishtp_driver_data_index { + ISHTP_DRIVER_DATA_NONE, + ISHTP_DRIVER_DATA_LNL_M, +}; + +#define ISH_FW_FILENAME_LNL_M "intel/ish/ish_lnlm.bin" + +static struct ishtp_driver_data ishtp_driver_data[] = { + [ISHTP_DRIVER_DATA_LNL_M] = { + .fw_filename = ISH_FW_FILENAME_LNL_M, + }, +}; + static const struct pci_device_id ish_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_CHV)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_BXT_Ax)}, @@ -46,7 +59,7 @@ static const struct pci_device_id ish_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_MTL_P)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_H)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_S)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_LNL_M)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_LNL_M), .driver_data = ISHTP_DRIVER_DATA_LNL_M}, {} }; MODULE_DEVICE_TABLE(pci, ish_pci_tbl); @@ -167,6 +180,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } hw = to_ish_hw(ishtp); ishtp->print_log = ish_event_tracer; + ishtp->driver_data = &ishtp_driver_data[ent->driver_data]; /* mapping IO device memory */ hw->mem_addr = pcim_iomap_table(pdev)[0]; @@ -377,3 +391,5 @@ MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver"); MODULE_LICENSE("GPL"); + +MODULE_FIRMWARE(ISH_FW_FILENAME_LNL_M); diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index 32142c7d9a04..ed294bf0bc8f 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -122,12 +122,29 @@ struct ishtp_hw_ops { bool (*dma_no_cache_snooping)(struct ishtp_device *dev); }; +/** + * struct ishtp_driver_data - Driver-specific data for ISHTP devices + * + * This structure holds driver-specific data that can be associated with each + * ISHTP device instance. It allows for the storage of data that is unique to + * a particular driver or hardware variant. + * + * @fw_filename: The firmware filename associated with a specific hardware + * variant of the Intel Integrated Sensor Hub (ISH). This allows + * the driver to load the correct firmware based on the device's + * hardware variant. + */ +struct ishtp_driver_data { + char *fw_filename; +}; + /** * struct ishtp_device - ISHTP private device struct */ struct ishtp_device { struct device *devc; /* pointer to lowest device */ struct pci_dev *pdev; /* PCI device to get device ids */ + struct ishtp_driver_data *driver_data; /* pointer to driver-specific data */ /* waitq for waiting for suspend response */ wait_queue_head_t suspend_wait; -- cgit v1.2.3 From 579a267e4617d705f6c795e5e755b01f1f87eff3 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 6 May 2024 09:30:39 +0800 Subject: HID: intel-ish-hid: Implement loading firmware from host feature Starting from the Lunar Lake generation, the ISH firmware has been divided into two components for better space optimization and increased flexibility. These components include a bootloader that is integrated into the BIOS, and a main firmware that is stored within the operating system's file system. Introduce support for loading ISH main firmware from host. This feature is applicable for Lunar Lake and later generation. Current intel-ishtp-loader, is designed for Chrome OS based systems which uses core boot and has different firmware loading method. For non chrome systems the ISH firmware loading uses different method. Key differences include: 1. The new method utilizes ISHTP capability/fixed client to enumerate the firmware loader function. It does not require a connection or flow control, unlike the method used in Chrome OS, which is enumerated as an ISHTP dynamic client driver, necessitating connect/disconnect operations and flow control. 2. The new method employs a table to describe firmware fragments, which are sent to ISH in a single operation. Conversely, the Chrome OS method sends firmware fragments in multiple operations within a loop, sending only one fragment at a time. Additionally, address potential error scenarios to ensure graceful failure handling. - Firmware Not Found: Triggers if request_firmware() fails, leaving ISH in a waiting state. Recovery: Re-insmod the ISH drivers to retry. - DMA Buffer Allocation Failure: Occurs during prepare_dma_bufs(), leading to ISH waiting state. Allocated resources are released. Recovery: Re-insmod the ISH drivers to retry. - Incorrect Firmware Image: Causes ISH to refuse loading after three failed attempts. Recovery: A platform reset is required. Please refer to the [Documentation](Documentation/hid/intel-ish-hid.rst) for the details on flows. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/Makefile | 1 + drivers/hid/intel-ish-hid/ishtp/hbm.c | 21 +++ drivers/hid/intel-ish-hid/ishtp/init.c | 8 + drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 11 ++ drivers/hid/intel-ish-hid/ishtp/loader.c | 275 ++++++++++++++++++++++++++++ drivers/hid/intel-ish-hid/ishtp/loader.h | 226 +++++++++++++++++++++++ 6 files changed, 542 insertions(+) create mode 100644 drivers/hid/intel-ish-hid/ishtp/loader.c create mode 100644 drivers/hid/intel-ish-hid/ishtp/loader.h (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/Makefile b/drivers/hid/intel-ish-hid/Makefile index f0a82b1c7cb9..a927b224cd44 100644 --- a/drivers/hid/intel-ish-hid/Makefile +++ b/drivers/hid/intel-ish-hid/Makefile @@ -11,6 +11,7 @@ intel-ishtp-objs += ishtp/client.o intel-ishtp-objs += ishtp/bus.o intel-ishtp-objs += ishtp/dma-if.o intel-ishtp-objs += ishtp/client-buffers.o +intel-ishtp-objs += ishtp/loader.o obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-ipc.o intel-ish-ipc-objs := ipc/ipc.o diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c index 9c031a06e4c4..8ee5467127d8 100644 --- a/drivers/hid/intel-ish-hid/ishtp/hbm.c +++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c @@ -13,6 +13,7 @@ #include "ishtp-dev.h" #include "hbm.h" #include "client.h" +#include "loader.h" /** * ishtp_hbm_fw_cl_allocate() - Allocate FW clients @@ -570,6 +571,10 @@ void ishtp_hbm_dispatch(struct ishtp_device *dev, return; } + /* Start firmware loading process if it has loader capability */ + if (version_res->host_version_supported & ISHTP_SUPPORT_CAP_LOADER) + schedule_work(&dev->work_fw_loader); + dev->version.major_version = HBM_MAJOR_VERSION; dev->version.minor_version = HBM_MINOR_VERSION; if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS && @@ -864,6 +869,20 @@ eoi: return; } +/** + * ishtp_loader_recv_msg() - Receive a message from the ISHTP device + * @dev: The ISHTP device + * @buf: The buffer containing the message + */ +static void ishtp_loader_recv_msg(struct ishtp_device *dev, void *buf) +{ + if (dev->fw_loader_rx_buf) + memcpy(dev->fw_loader_rx_buf, buf, dev->fw_loader_rx_size); + + dev->fw_loader_received = true; + wake_up_interruptible(&dev->wait_loader_recvd_msg); +} + /** * recv_fixed_cl_msg() - Receive fixed client message * @dev: ISHTP device instance @@ -890,6 +909,8 @@ void recv_fixed_cl_msg(struct ishtp_device *dev, else dev_err(dev->devc, "unknown fixed client msg [%02X]\n", msg_hdr->cmd); + } else if (ishtp_hdr->fw_addr == ISHTP_LOADER_CLIENT_ADDR) { + ishtp_loader_recv_msg(dev, rd_msg_buf); } } diff --git a/drivers/hid/intel-ish-hid/ishtp/init.c b/drivers/hid/intel-ish-hid/ishtp/init.c index 02a00cc2dd11..07fdd52e4c5e 100644 --- a/drivers/hid/intel-ish-hid/ishtp/init.c +++ b/drivers/hid/intel-ish-hid/ishtp/init.c @@ -5,12 +5,14 @@ * Copyright (c) 2003-2016, Intel Corporation. */ +#include #include #include #include #include "ishtp-dev.h" #include "hbm.h" #include "client.h" +#include "loader.h" /** * ishtp_dev_state_str() -Convert to string format @@ -51,6 +53,8 @@ const char *ishtp_dev_state_str(int state) */ void ishtp_device_init(struct ishtp_device *dev) { + int ret; + dev->dev_state = ISHTP_DEV_INITIALIZING; INIT_LIST_HEAD(&dev->cl_list); INIT_LIST_HEAD(&dev->device_list); @@ -59,6 +63,7 @@ void ishtp_device_init(struct ishtp_device *dev) spin_lock_init(&dev->rd_msg_spinlock); init_waitqueue_head(&dev->wait_hbm_recvd_msg); + init_waitqueue_head(&dev->wait_loader_recvd_msg); spin_lock_init(&dev->read_list_spinlock); spin_lock_init(&dev->device_lock); spin_lock_init(&dev->device_list_lock); @@ -76,6 +81,9 @@ void ishtp_device_init(struct ishtp_device *dev) INIT_LIST_HEAD(&dev->read_list.list); + ret = devm_work_autocancel(dev->devc, &dev->work_fw_loader, ishtp_loader_work); + if (ret) + dev_err_probe(dev->devc, ret, "Failed to initialise FW loader work\n"); } EXPORT_SYMBOL(ishtp_device_init); diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index ed294bf0bc8f..181838c3d7ac 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -164,6 +164,17 @@ struct ishtp_device { struct hbm_version version; int transfer_path; /* Choice of transfer path: IPC or DMA */ + /* work structure for scheduling firmware loading tasks */ + struct work_struct work_fw_loader; + /* waitq for waiting for command response from the firmware loader */ + wait_queue_head_t wait_loader_recvd_msg; + /* indicating whether a message from the firmware loader has been received */ + bool fw_loader_received; + /* pointer to a buffer for receiving messages from the firmware loader */ + void *fw_loader_rx_buf; + /* size of the buffer pointed to by fw_loader_rx_buf */ + int fw_loader_rx_size; + /* ishtp device states */ enum ishtp_dev_state dev_state; enum ishtp_hbm_state hbm_state; diff --git a/drivers/hid/intel-ish-hid/ishtp/loader.c b/drivers/hid/intel-ish-hid/ishtp/loader.c new file mode 100644 index 000000000000..993f8b390e57 --- /dev/null +++ b/drivers/hid/intel-ish-hid/ishtp/loader.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ISHTP firmware loader function + * + * Copyright (c) 2024, Intel Corporation. + * + * This module implements the functionality to load the main ISH firmware from the host, starting + * with the Lunar Lake generation. It leverages a new method that enhances space optimization and + * flexibility by dividing the ISH firmware into a bootloader and main firmware. + * + * Please refer to the [Documentation](Documentation/hid/intel-ish-hid.rst) for the details on + * flows. + * + * Additionally, address potential error scenarios to ensure graceful failure handling. + * - Firmware Image Not Found: + * Occurs when `request_firmware()` cannot locate the firmware image. The ISH firmware will + * remain in a state awaiting firmware loading from the host, with no further action from + * the ISHTP driver. + * Recovery: Re-insmod the ISH drivers allows for a retry of the firmware loading from the host. + * + * - DMA Buffer Allocation Failure: + * This happens if allocating a DMA buffer during `prepare_dma_bufs()` fails. The ISH firmware + * will stay in a waiting state, and the ISHTP driver will release any allocated DMA buffers and + * firmware without further actions. + * Recovery: Re-insmod the ISH drivers allows for a retry of the firmware loading from the host. + * + * - Incorrect Firmware Image: + * Using an incorrect firmware image will initiate the firmware loading process but will + * eventually be refused by the ISH firmware after three unsuccessful attempts, indicated by + * returning an error code. The ISHTP driver will stop attempting after three tries. + * Recovery: A platform reset is required to retry firmware loading from the host. + */ + +#define dev_fmt(fmt) "ISH loader: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hbm.h" +#include "loader.h" + +/** + * loader_write_message() - Write a message to the ISHTP device + * @dev: The ISHTP device + * @buf: The buffer containing the message + * @len: The length of the message + * + * Return: 0 on success, negative error code on failure + */ +static int loader_write_message(struct ishtp_device *dev, void *buf, int len) +{ + struct ishtp_msg_hdr ishtp_hdr = { + .fw_addr = ISHTP_LOADER_CLIENT_ADDR, + .length = len, + .msg_complete = 1, + }; + + dev->fw_loader_received = false; + + return ishtp_write_message(dev, &ishtp_hdr, buf); +} + +/** + * loader_xfer_cmd() - Transfer a command to the ISHTP device + * @dev: The ISHTP device + * @req: The request buffer + * @req_len: The length of the request + * @resp: The response buffer + * @resp_len: The length of the response + * + * Return: 0 on success, negative error code on failure + */ +static int loader_xfer_cmd(struct ishtp_device *dev, void *req, int req_len, + void *resp, int resp_len) +{ + struct loader_msg_header *req_hdr = req; + struct loader_msg_header *resp_hdr = resp; + struct device *devc = dev->devc; + int rv; + + dev->fw_loader_rx_buf = resp; + dev->fw_loader_rx_size = resp_len; + + rv = loader_write_message(dev, req, req_len); + if (rv < 0) { + dev_err(devc, "write cmd %u failed:%d\n", req_hdr->command, rv); + return rv; + } + + /* Wait the ACK */ + wait_event_interruptible_timeout(dev->wait_loader_recvd_msg, dev->fw_loader_received, + ISHTP_LOADER_TIMEOUT); + dev->fw_loader_rx_size = 0; + dev->fw_loader_rx_buf = NULL; + if (!dev->fw_loader_received) { + dev_err(devc, "wait response of cmd %u timeout\n", req_hdr->command); + return -ETIMEDOUT; + } + + if (!resp_hdr->is_response) { + dev_err(devc, "not a response for %u\n", req_hdr->command); + return -EBADMSG; + } + + if (req_hdr->command != resp_hdr->command) { + dev_err(devc, "unexpected cmd response %u:%u\n", req_hdr->command, + resp_hdr->command); + return -EBADMSG; + } + + if (resp_hdr->status) { + dev_err(devc, "cmd %u failed %u\n", req_hdr->command, resp_hdr->status); + return -EIO; + } + + return 0; +} + +/** + * release_dma_bufs() - Release the DMA buffer for transferring firmware fragments + * @dev: The ISHTP device + * @fragment: The ISHTP firmware fragment descriptor + * @dma_bufs: The array of DMA fragment buffers + * @fragment_size: The size of a single DMA fragment + */ +static void release_dma_bufs(struct ishtp_device *dev, + struct loader_xfer_dma_fragment *fragment, + void **dma_bufs, u32 fragment_size) +{ + int i; + + for (i = 0; i < FRAGMENT_MAX_NUM; i++) { + if (dma_bufs[i]) { + dma_free_coherent(dev->devc, fragment_size, dma_bufs[i], + fragment->fragment_tbl[i].ddr_adrs); + dma_bufs[i] = NULL; + } + } +} + +/** + * prepare_dma_bufs() - Prepare the DMA buffer for transferring firmware fragments + * @dev: The ISHTP device + * @ish_fw: The ISH firmware + * @fragment: The ISHTP firmware fragment descriptor + * @dma_bufs: The array of DMA fragment buffers + * @fragment_size: The size of a single DMA fragment + * + * Return: 0 on success, negative error code on failure + */ +static int prepare_dma_bufs(struct ishtp_device *dev, + const struct firmware *ish_fw, + struct loader_xfer_dma_fragment *fragment, + void **dma_bufs, u32 fragment_size) +{ + u32 offset = 0; + int i; + + for (i = 0; i < fragment->fragment_cnt && offset < ish_fw->size; i++) { + dma_bufs[i] = dma_alloc_coherent(dev->devc, fragment_size, + &fragment->fragment_tbl[i].ddr_adrs, GFP_KERNEL); + if (!dma_bufs[i]) + return -ENOMEM; + + fragment->fragment_tbl[i].length = clamp(ish_fw->size - offset, 0, fragment_size); + fragment->fragment_tbl[i].fw_off = offset; + memcpy(dma_bufs[i], ish_fw->data + offset, fragment->fragment_tbl[i].length); + clflush_cache_range(dma_bufs[i], fragment_size); + + offset += fragment->fragment_tbl[i].length; + } + + return 0; +} + +/** + * ishtp_loader_work() - Load the ISHTP firmware + * @work: The work structure + * + * The ISH Loader attempts to load firmware by sending a series of commands + * to the ISH device. If a command fails to be acknowledged by the ISH device, + * the loader will retry sending the command, up to a maximum of + * ISHTP_LOADER_RETRY_TIMES. + * + * After the maximum number of retries has been reached without success, the + * ISH bootloader will return an error status code and will no longer respond + * to the driver's commands. This behavior indicates that the ISH Loader has + * encountered a critical error during the firmware loading process. + * + * In such a case, where the ISH bootloader is unresponsive after all retries + * have been exhausted, a platform reset is required to restore communication + * with the ISH device and to recover from this error state. + */ +void ishtp_loader_work(struct work_struct *work) +{ + DEFINE_RAW_FLEX(struct loader_xfer_dma_fragment, fragment, fragment_tbl, FRAGMENT_MAX_NUM); + struct ishtp_device *dev = container_of(work, struct ishtp_device, work_fw_loader); + struct loader_xfer_query query = { + .header.command = LOADER_CMD_XFER_QUERY, + }; + struct loader_start start = { + .header.command = LOADER_CMD_START, + }; + union loader_recv_message recv_msg; + char *filename = dev->driver_data->fw_filename; + const struct firmware *ish_fw; + void *dma_bufs[FRAGMENT_MAX_NUM] = {}; + u32 fragment_size; + int retry = ISHTP_LOADER_RETRY_TIMES; + int rv; + + rv = request_firmware(&ish_fw, filename, dev->devc); + if (rv < 0) { + dev_err(dev->devc, "request firmware %s failed:%d\n", filename, rv); + return; + } + + fragment->fragment.header.command = LOADER_CMD_XFER_FRAGMENT; + fragment->fragment.xfer_mode = LOADER_XFER_MODE_DMA; + fragment->fragment.is_last = 1; + fragment->fragment.size = ish_fw->size; + /* Calculate the size of a single DMA fragment */ + fragment_size = PFN_ALIGN(DIV_ROUND_UP(ish_fw->size, FRAGMENT_MAX_NUM)); + /* Calculate the count of DMA fragments */ + fragment->fragment_cnt = DIV_ROUND_UP(ish_fw->size, fragment_size); + + rv = prepare_dma_bufs(dev, ish_fw, fragment, dma_bufs, fragment_size); + if (rv) { + dev_err(dev->devc, "prepare DMA buffer failed.\n"); + goto out; + } + + do { + query.image_size = ish_fw->size; + rv = loader_xfer_cmd(dev, &query, sizeof(query), recv_msg.raw_data, + sizeof(struct loader_xfer_query_ack)); + if (rv) + continue; /* try again if failed */ + + dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", + recv_msg.query_ack.version_major, + recv_msg.query_ack.version_minor, + recv_msg.query_ack.version_hotfix, + recv_msg.query_ack.version_build); + + rv = loader_xfer_cmd(dev, fragment, + struct_size(fragment, fragment_tbl, fragment->fragment_cnt), + recv_msg.raw_data, sizeof(struct loader_xfer_fragment_ack)); + if (rv) + continue; /* try again if failed */ + + rv = loader_xfer_cmd(dev, &start, sizeof(start), recv_msg.raw_data, + sizeof(struct loader_start_ack)); + if (rv) + continue; /* try again if failed */ + + dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); + break; + } while (--retry); + +out: + release_dma_bufs(dev, fragment, dma_bufs, fragment_size); + release_firmware(ish_fw); +} diff --git a/drivers/hid/intel-ish-hid/ishtp/loader.h b/drivers/hid/intel-ish-hid/ishtp/loader.h new file mode 100644 index 000000000000..7aa45ebc3f7b --- /dev/null +++ b/drivers/hid/intel-ish-hid/ishtp/loader.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ISHTP firmware loader header + * + * Copyright (c) 2024, Intel Corporation. + */ + +#ifndef _ISHTP_LOADER_H_ +#define _ISHTP_LOADER_H_ + +#include +#include +#include + +#include "ishtp-dev.h" + +struct work_struct; + +#define LOADER_MSG_SIZE \ + (IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr)) + +/* + * ISHTP firmware loader protocol definition + */ +#define LOADER_CMD_XFER_QUERY 0 /* SW -> FW */ +#define LOADER_CMD_XFER_FRAGMENT 1 /* SW -> FW */ +#define LOADER_CMD_START 2 /* SW -> FW */ + +/* Only support DMA mode */ +#define LOADER_XFER_MODE_DMA BIT(0) + +/** + * struct loader_msg_header - ISHTP firmware loader message header + * @command: Command type + * @is_response: Indicates if the message is a response + * @has_next: Indicates if there is a next message + * @reserved: Reserved for future use + * @status: Status of the message + */ +struct loader_msg_header { + __le32 command:7; + __le32 is_response:1; + __le32 has_next:1; + __le32 reserved:15; + __le32 status:8; +}; + +/** + * struct loader_xfer_query - ISHTP firmware loader transfer query packet + * @header: Header of the message + * @image_size: Size of the image + */ +struct loader_xfer_query { + struct loader_msg_header header; + __le32 image_size; +}; + +/** + * struct loader_version - ISHTP firmware loader version + * @value: Value of the version + * @major: Major version + * @minor: Minor version + * @hotfix: Hotfix version + * @build: Build version + */ +struct loader_version { + union { + __le32 value; + struct { + __u8 major; + __u8 minor; + __u8 hotfix; + __u8 build; + }; + }; +}; + +/** + * struct loader_capability - ISHTP firmware loader capability + * @max_fw_image_size: Maximum firmware image size + * @support_mode: Support mode + * @reserved: Reserved for future use + * @platform: Platform + * @max_dma_buf_size: Maximum DMA buffer size, multiples of 4096 + */ +struct loader_capability { + __le32 max_fw_image_size; + __le16 support_mode; + __u8 reserved; + __u8 platform; + __le32 max_dma_buf_size; +}; + +/** + * struct loader_xfer_query_ack - ISHTP firmware loader transfer query acknowledgment + * @header: Header of the message + * @version_major: ISH Major version + * @version_minor: ISH Minor version + * @version_hotfix: ISH Hotfix version + * @version_build: ISH Build version + * @protocol_version: Protocol version + * @loader_version: Loader version + * @capability: Loader capability + */ +struct loader_xfer_query_ack { + struct loader_msg_header header; + __le16 version_major; + __le16 version_minor; + __le16 version_hotfix; + __le16 version_build; + __le32 protocol_version; + struct loader_version loader_version; + struct loader_capability capability; +}; + +/** + * struct loader_xfer_fragment - ISHTP firmware loader transfer fragment + * @header: Header of the message + * @xfer_mode: Transfer mode + * @offset: Offset + * @size: Size + * @is_last: Is last + */ +struct loader_xfer_fragment { + struct loader_msg_header header; + __le32 xfer_mode; + __le32 offset; + __le32 size; + __le32 is_last; +}; + +/** + * struct loader_xfer_fragment_ack - ISHTP firmware loader transfer fragment acknowledgment + * @header: Header of the message + */ +struct loader_xfer_fragment_ack { + struct loader_msg_header header; +}; + +/** + * struct fragment_dscrpt - ISHTP firmware loader fragment descriptor + * @ddr_adrs: The address in host DDR + * @fw_off: The offset of the fragment in the fw image + * @length: The length of the fragment + */ +struct fragment_dscrpt { + __le64 ddr_adrs; + __le32 fw_off; + __le32 length; +}; + +#define FRAGMENT_MAX_NUM \ + ((LOADER_MSG_SIZE - sizeof(struct loader_xfer_dma_fragment)) / \ + sizeof(struct fragment_dscrpt)) + +/** + * struct loader_xfer_dma_fragment - ISHTP firmware loader transfer DMA fragment + * @fragment: Fragment + * @fragment_cnt: How many descriptors in the fragment_tbl + * @fragment_tbl: Fragment table + */ +struct loader_xfer_dma_fragment { + struct loader_xfer_fragment fragment; + __le32 fragment_cnt; + struct fragment_dscrpt fragment_tbl[] __counted_by(fragment_cnt); +}; + +/** + * struct loader_start - ISHTP firmware loader start + * @header: Header of the message + */ +struct loader_start { + struct loader_msg_header header; +}; + +/** + * struct loader_start_ack - ISHTP firmware loader start acknowledgment + * @header: Header of the message + */ +struct loader_start_ack { + struct loader_msg_header header; +}; + +union loader_recv_message { + struct loader_xfer_query_ack query_ack; + struct loader_xfer_fragment_ack fragment_ack; + struct loader_start_ack start_ack; + __u8 raw_data[LOADER_MSG_SIZE]; +}; + +/* + * ISHTP firmware loader internal use + */ +/* ISHTP firmware loader command timeout */ +#define ISHTP_LOADER_TIMEOUT msecs_to_jiffies(100) + +/* ISHTP firmware loader retry times */ +#define ISHTP_LOADER_RETRY_TIMES 3 + +/** + * struct ish_firmware_variant - ISH firmware variant + * @device: PCI Device ID + * @filename: The firmware file name + */ +struct ish_firmware_variant { + unsigned short device; + const char *filename; +}; + +/* + * ISHTP firmware loader API for ISHTP hbm + */ + +/* ISHTP capability bit for firmware loader */ +#define ISHTP_SUPPORT_CAP_LOADER BIT(4) + +/* Firmware loader address */ +#define ISHTP_LOADER_CLIENT_ADDR 16 + +/** + * ishtp_loader_work - The work function to start the firmware loading process + * @work: The work structure + */ +void ishtp_loader_work(struct work_struct *work); + +#endif /* _ISHTP_LOADER_H_ */ -- cgit v1.2.3 From 25247cf689db28a9a7bc7efd4efc7441f763a74a Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 6 May 2024 09:30:40 +0800 Subject: HID: intel-ish-hid: handler multiple MNG_RESET_NOTIFY messages This patch enhances the firmware reset handler in the Intel Integrated Sensor Hub (ISH) driver. Previously, the ISH firmware would send a MNG_RESET_NOTIFY message in response to an empty IPC message from the ish_wakeup function. With the introduction of the feature to load ISH firmware from the host on the LunarLake platform, the ISH bootloader now involves the IPC function. This results in an additional MNG_RESET_NOTIFY message being sent by ISH bootloader after power on. Consequently, the driver receives two MNG_RESET_NOTIFY messages during system boot up. This can disrupt the dev->dev_state during the first reset flow due to the subsequent reset notify message. To address this, the patch modifies the fw_reset_work_fn function to skip the execution of ishtp_reset_compl_handler during the first reset flow if a reset is pending. The ishtp_reset_compl_handler will then be executed during the second reset flow, ensuring the dev->dev_state is not disrupted. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/ipc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 7cc412798fdf..61f68e7a9b25 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -546,11 +546,11 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) /** * fw_reset_work_fn() - FW reset worker function - * @unused: not used + * @work: Work item * * Call ish_fw_reset_handler to complete FW reset */ -static void fw_reset_work_fn(struct work_struct *unused) +static void fw_reset_work_fn(struct work_struct *work) { int rv; @@ -562,7 +562,8 @@ static void fw_reset_work_fn(struct work_struct *unused) wake_up_interruptible(&ishtp_dev->wait_hw_ready); /* ISHTP notification in IPC_RESET sequence completion */ - ishtp_reset_compl_handler(ishtp_dev); + if (!work_pending(work)) + ishtp_reset_compl_handler(ishtp_dev); } else dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n", rv); -- cgit v1.2.3 From 6baa4524027fd64d7ca524e1717c88c91a354b93 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Mon, 29 Apr 2024 16:54:22 +0800 Subject: HID: intel-ish-hid: ipc: Add check for pci_alloc_irq_vectors Add a check for the return value of pci_alloc_irq_vectors() and return error if it fails. [jkosina@suse.com: reworded changelog based on Srinivas' suggestion] Fixes: 74fbc7d371d9 ("HID: intel-ish-hid: add MSI interrupt support") Signed-off-by: Chen Ni Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 56bd4f02f319..4b8232360cc4 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -173,6 +173,11 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* request and enable interrupt */ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + dev_err(dev, "ISH: Failed to allocate IRQ vectors\n"); + return ret; + } + if (!pdev->msi_enabled && !pdev->msix_enabled) irq_flag = IRQF_SHARED; -- cgit v1.2.3 From d2b34fa81445193532e7012106f60426de3b3718 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 7 May 2024 08:36:56 +0200 Subject: HID: i2c-hid: Remove unused label in i2c_hid_set_power This label was left behind when the wake-up logic was moved from i2c_hid_set_power to i2c_hid_probe_address. Clean it up as it causes warnings-as-errors builds to fail. Fixes: bb1033c8a3ea ("HID: i2c-hid: Use address probe to wake on resume") Reported-by: Stephen Rothwell Signed-off-by: Kenny Levinsen Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 13666c27b02e..aa460f67c7b5 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -413,8 +413,6 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) dev_err(&ihid->client->dev, "failed to change power setting.\n"); -set_pwr_exit: - /* * The HID over I2C specification states that if a DEVICE needs time * after the PWR_ON request, it should utilise CLOCK stretching. -- cgit v1.2.3 From f273cbf831d4359b602980a36e3d0c02a16104f9 Mon Sep 17 00:00:00 2001 From: David Yang Date: Thu, 2 May 2024 12:23:31 +0800 Subject: HID: kye: Change Device Usage from Puck to Mouse Change device type because a. it is exactly a mouse, with left/right buttons and scroll wheel; b. it does not have visible marks or crosshairs, thus does not provide higher accuracy than stylus. Signed-off-by: David Yang Signed-off-by: Jiri Kosina --- drivers/hid/hid-kye.c | 75 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 31 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index eb9bf2829937..70ceb9437332 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -209,7 +209,7 @@ static const __u8 pensketch_t609a_control_rdesc[] = { 0xC0 /* End Collection */ }; -/* Fix indexes in kye_tablet_fixup if you change this */ +/* Fix indexes in kye_tablet_fixup() if you change this */ static const __u8 kye_tablet_rdesc[] = { 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x09, 0x01, /* Usage (01h), */ @@ -262,12 +262,16 @@ static const __u8 kye_tablet_rdesc[] = { 0x27, 0xFF, 0x07, 0x00, 0x00, /* Logical Maximum (2047), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ - 0xC0, /* End Collection, */ - 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x21, /* Usage (Puck), */ + 0xC0 /* End Collection, */ +}; + +/* Fix indexes in kye_tablet_fixup() if you change this */ +static const __u8 kye_tablet_mouse_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x02, /* Usage (Mouse), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x11, /* Report ID (17), */ - 0x09, 0x21, /* Usage (Puck), */ + 0x09, 0x01, /* Usage (Pointer), */ 0xA0, /* Collection (Physical), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ @@ -280,7 +284,7 @@ static const __u8 kye_tablet_rdesc[] = { 0x95, 0x04, /* Report Count (4), */ 0x81, 0x01, /* Input (Constant), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x32, /* Usage (In Range), */ + 0x09, 0x37, /* Usage (Data Valid), */ 0x95, 0x01, /* Report Count (1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ @@ -317,7 +321,7 @@ static const struct kye_tablet_info { __s32 y_physical_maximum; __s8 unit_exponent; __s8 unit; - bool has_punk; + bool has_mouse; unsigned int control_rsize; const __u8 *control_rdesc; } kye_tablets_info[] = { @@ -402,7 +406,7 @@ static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *kye_tablet_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { const struct kye_tablet_info *info; - unsigned int newsize; + __u8 *newdesc = rdesc; if (*rsize < sizeof(kye_tablet_rdesc)) { hid_warn(hdev, @@ -420,36 +424,45 @@ static __u8 *kye_tablet_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int return rdesc; } - newsize = info->has_punk ? sizeof(kye_tablet_rdesc) : 112; - memcpy(rdesc, kye_tablet_rdesc, newsize); - - put_unaligned_le32(info->x_logical_maximum, rdesc + 66); - put_unaligned_le32(info->x_physical_maximum, rdesc + 72); - rdesc[77] = info->unit; - rdesc[79] = info->unit_exponent; - put_unaligned_le32(info->y_logical_maximum, rdesc + 87); - put_unaligned_le32(info->y_physical_maximum, rdesc + 92); - put_unaligned_le32(info->pressure_logical_maximum, rdesc + 104); - - if (info->has_punk) { - put_unaligned_le32(info->x_logical_maximum, rdesc + 156); - put_unaligned_le32(info->x_physical_maximum, rdesc + 162); - rdesc[167] = info->unit; - rdesc[169] = info->unit_exponent; - put_unaligned_le32(info->y_logical_maximum, rdesc + 177); - put_unaligned_le32(info->y_physical_maximum, rdesc + 182); + memcpy(newdesc, kye_tablet_rdesc, sizeof(kye_tablet_rdesc)); + + put_unaligned_le32(info->x_logical_maximum, newdesc + 66); + put_unaligned_le32(info->x_physical_maximum, newdesc + 72); + newdesc[77] = info->unit; + newdesc[79] = info->unit_exponent; + put_unaligned_le32(info->y_logical_maximum, newdesc + 87); + put_unaligned_le32(info->y_physical_maximum, newdesc + 92); + put_unaligned_le32(info->pressure_logical_maximum, newdesc + 104); + + newdesc += sizeof(kye_tablet_rdesc); + + if (info->has_mouse) { + if (newdesc + sizeof(kye_tablet_mouse_rdesc) > rdesc + *rsize) + hid_err(hdev, "control desc unexpectedly large\n"); + else { + memcpy(newdesc, kye_tablet_mouse_rdesc, sizeof(kye_tablet_mouse_rdesc)); + + put_unaligned_le32(info->x_logical_maximum, newdesc + 44); + put_unaligned_le32(info->x_physical_maximum, newdesc + 50); + newdesc[55] = info->unit; + newdesc[57] = info->unit_exponent; + put_unaligned_le32(info->y_logical_maximum, newdesc + 65); + put_unaligned_le32(info->y_physical_maximum, newdesc + 70); + + newdesc += sizeof(kye_tablet_mouse_rdesc); + } } if (info->control_rsize) { - if (newsize + info->control_rsize > *rsize) - hid_err(hdev, "control rdesc unexpectedly large"); + if (newdesc + info->control_rsize > rdesc + *rsize) + hid_err(hdev, "control desc unexpectedly large\n"); else { - memcpy(rdesc + newsize, info->control_rdesc, info->control_rsize); - newsize += info->control_rsize; + memcpy(newdesc, info->control_rdesc, info->control_rsize); + newdesc += info->control_rsize; } } - *rsize = newsize; + *rsize = newdesc - rdesc; return rdesc; } -- cgit v1.2.3 From 6856f079cd45c7c085a8062a1b4839d9567e6f48 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 7 May 2024 12:40:43 +0530 Subject: HID: amd_sfh: Modify and log error only if case of functionality failures Modify log messages, but only log errors when sensors are missing or a true failure occurs to avoid misleading "failed" messages. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 5 +---- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c | 7 ++++--- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 9e97c26c4482..0c28ca349bcd 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -333,14 +333,11 @@ static const struct dmi_system_id dmi_nodevs[] = { static void sfh1_1_init_work(struct work_struct *work) { struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work); - struct pci_dev *pdev = mp2->pdev; int rc; rc = mp2->sfh1_1_ops->init(mp2); - if (rc) { - dev_err(&pdev->dev, "sfh1_1_init failed err %d\n", rc); + if (rc) return; - } amd_sfh_clear_intr(mp2); mp2->init_done = 1; diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c index 5b24d5f63701..f46f9c670c6b 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c @@ -202,7 +202,7 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata) } if (!cl_data->is_any_sensor_enabled) { - dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", + dev_warn(dev, "No sensor registered, sensors not enabled is %d\n", cl_data->is_any_sensor_enabled); rc = -EOPNOTSUPP; goto cleanup; @@ -320,7 +320,7 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2) memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) { - dev_dbg(dev, "failed to get sensors\n"); + dev_dbg(dev, "No sensor registered\n"); return -EOPNOTSUPP; } dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver); @@ -337,7 +337,8 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2) rc = amd_sfh1_1_hid_client_init(mp2); if (rc) { sfh_deinit_emp2(); - dev_err(dev, "amd_sfh1_1_hid_client_init failed\n"); + if ((rc != -ENODEV) && (rc != -EOPNOTSUPP)) + dev_err(dev, "amd_sfh1_1_hid_client_init failed\n"); return rc; } -- cgit v1.2.3 From 077e3e3bc84a51891e732507bbbd9acf6e0e4c8b Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 7 May 2024 12:40:44 +0530 Subject: HID: amd_sfh: Handle "no sensors" in PM operations Resume or suspend each sensor device based on the num_hid_devices. Therefore, add a check to handle the special case where no sensors are present. Fixes: 93ce5e0231d7 ("HID: amd_sfh: Implement SFH1.1 functionality") Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c index f46f9c670c6b..621793d92464 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c @@ -227,6 +227,11 @@ static void amd_sfh_resume(struct amd_mp2_dev *mp2) struct amd_mp2_sensor_info info; int i, status; + if (!cl_data->is_any_sensor_enabled) { + amd_sfh_clear_intr(mp2); + return; + } + for (i = 0; i < cl_data->num_hid_devices; i++) { if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { info.sensor_idx = cl_data->sensor_idx[i]; @@ -252,6 +257,11 @@ static void amd_sfh_suspend(struct amd_mp2_dev *mp2) struct amdtp_cl_data *cl_data = mp2->cl_data; int i, status; + if (!cl_data->is_any_sensor_enabled) { + amd_sfh_clear_intr(mp2); + return; + } + for (i = 0; i < cl_data->num_hid_devices; i++) { if (cl_data->sensor_idx[i] != HPD_IDX && cl_data->sensor_sts[i] == SENSOR_ENABLED) { -- cgit v1.2.3 From 7902ec988a9a6552b58d096df10605ed82d7bbc4 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 7 May 2024 12:40:45 +0530 Subject: HID: amd_sfh: Use amd_get_c2p_val() to read C2P register Newer processors support various MP2 register sets. Therefore, to ensure compatibility and obtain C2P data, use the amd_get_c2p_val(). Co-developed-by: Patil Rajesh Reddy Signed-off-by: Patil Rajesh Reddy Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c index 2de2668a0277..4676f060da26 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c @@ -97,7 +97,7 @@ static int amd_sfh_hpd_info(u8 *user_present) if (!emp2 || !emp2->dev_en.is_hpd_present) return -ENODEV; - hpdstatus.val = readl(emp2->mmio + AMD_C2P_MSG(4)); + hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4)); *user_present = hpdstatus.shpd.presence; return 0; -- cgit v1.2.3 From 04b3e5ab055553e074ea54ef316982b55cdde96b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:22 +0200 Subject: HID: bpf: add first in-tree HID-BPF fix for the XPPen Artist 24 This commit adds a fix for XPPen Artist 24 where the second button on the pen is used as an eraser. It's a "feature" from Microsoft, but it turns out that it's actually painful for artists. So we ship here a HID-BPF program that turns this second button into an actual button. Note that the HID-BPF program is not directly loaded by the kernel itself but by udev-hid-bpf[0]. But having the sources here allows us to also integrate tests into tools/testing/selftests/hid to ensure the HID-BPF program are actually tested. [0] https://gitlab.freedesktop.org/libevdev/udev-hid-bpf Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-2-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Makefile | 91 +++++++++++ drivers/hid/bpf/progs/README | 102 +++++++++++++ drivers/hid/bpf/progs/XPPen__Artist24.bpf.c | 229 ++++++++++++++++++++++++++++ drivers/hid/bpf/progs/hid_bpf.h | 15 ++ drivers/hid/bpf/progs/hid_bpf_helpers.h | 168 ++++++++++++++++++++ 5 files changed, 605 insertions(+) create mode 100644 drivers/hid/bpf/progs/Makefile create mode 100644 drivers/hid/bpf/progs/README create mode 100644 drivers/hid/bpf/progs/XPPen__Artist24.bpf.c create mode 100644 drivers/hid/bpf/progs/hid_bpf.h create mode 100644 drivers/hid/bpf/progs/hid_bpf_helpers.h (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/Makefile b/drivers/hid/bpf/progs/Makefile new file mode 100644 index 000000000000..63ed7e02adf1 --- /dev/null +++ b/drivers/hid/bpf/progs/Makefile @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0 +OUTPUT := .output +abs_out := $(abspath $(OUTPUT)) + +CLANG ?= clang +LLC ?= llc +LLVM_STRIP ?= llvm-strip + +TOOLS_PATH := $(abspath ../../../../tools) +BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool +BPFTOOL_OUTPUT := $(abs_out)/bpftool +DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool +BPFTOOL ?= $(DEFAULT_BPFTOOL) + +LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf +LIBBPF_OUTPUT := $(abs_out)/libbpf +LIBBPF_DESTDIR := $(LIBBPF_OUTPUT) +LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include +BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a + +INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi +CFLAGS := -g -Wall + +VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ + $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ + ../../../../vmlinux \ + /sys/kernel/btf/vmlinux \ + /boot/vmlinux-$(shell uname -r) +VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) +ifeq ($(VMLINUX_BTF),) +$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)") +endif + +ifeq ($(V),1) +Q = +msg = +else +Q = @ +msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))"; +MAKEFLAGS += --no-print-directory +submake_extras := feature_display=0 +endif + +.DELETE_ON_ERROR: + +.PHONY: all clean + +SOURCES = $(wildcard *.bpf.c) +TARGETS = $(SOURCES:.bpf.c=.bpf.o) + +all: $(TARGETS) + +clean: + $(call msg,CLEAN) + $(Q)rm -rf $(OUTPUT) $(TARGETS) + +%.bpf.o: %.bpf.c vmlinux.h $(BPFOBJ) | $(OUTPUT) + $(call msg,BPF,$@) + $(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \ + -c $(filter %.c,$^) -o $@ && \ + $(LLVM_STRIP) -g $@ + +vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR) +ifeq ($(VMLINUX_H),) + $(call msg,GEN,,$@) + $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@ +else + $(call msg,CP,,$@) + $(Q)cp "$(VMLINUX_H)" $@ +endif + +$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT): + $(call msg,MKDIR,$@) + $(Q)mkdir -p $@ + +$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \ + OUTPUT=$(abspath $(dir $@))/ prefix= \ + DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers + +ifeq ($(CROSS_COMPILE),) +$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \ + OUTPUT=$(BPFTOOL_OUTPUT)/ \ + LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \ + LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap +else +$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT) + $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \ + OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap +endif diff --git a/drivers/hid/bpf/progs/README b/drivers/hid/bpf/progs/README new file mode 100644 index 000000000000..20b0928f385b --- /dev/null +++ b/drivers/hid/bpf/progs/README @@ -0,0 +1,102 @@ +# HID-BPF programs + +This directory contains various fixes for devices. They add new features or +fix some behaviors without being entirely mandatory. It is better to load them +when you have such a device, but they should not be a requirement for a device +to be working during the boot stage. + +The .bpf.c files provided here are not automatically compiled in the kernel. +They should be loaded in the kernel by `udev-hid-bpf`: + +https://gitlab.freedesktop.org/libevdev/udev-hid-bpf + +The main reasons for these fixes to be here is to have a central place to +"upstream" them, but also this way we can test them thanks to the HID +selftests. + +Once a .bpf.c file is accepted here, it is duplicated in `udev-hid-bpf` +in the `src/bpf/stable` directory, and distributions are encouraged to +only ship those bpf objects. So adding a file here should eventually +land in distributions when they update `udev-hid-bpf` + +## Compilation + +Just run `make` + +## Installation + +### Automated way + +Just run `sudo udev-hid-bpf install ./my-awesome-fix.bpf.o` + +### Manual way + +- copy the `.bpf.o` you want in `/etc/udev-hid-bpf/` +- create a new udev rule to automatically load it + +The following should do the trick (assuming udev-hid-bpf is available in +/usr/bin): + +``` +$> cp xppen-ArtistPro16Gen2.bpf.o /etc/udev-hid-bpf/ +$> udev-hid-bpf inspect xppen-ArtistPro16Gen2.bpf.o +[ + { + "name": "xppen-ArtistPro16Gen2.bpf.o", + "devices": [ + { + "bus": "0x0003", + "group": "0x0001", + "vid": "0x28BD", + "pid": "0x095A" + }, + { + "bus": "0x0003", + "group": "0x0001", + "vid": "0x28BD", + "pid": "0x095B" + } + ], +... +$> cat /etc/udev/rules.d/99-load-hid-bpf-xppen-ArtistPro16Gen2.rules +ACTION!="add|remove", GOTO="hid_bpf_end" +SUBSYSTEM!="hid", GOTO="hid_bpf_end" + +# xppen-ArtistPro16Gen2.bpf.o +ACTION=="add",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095A", RUN{program}+="/usr/local/bin/udev-hid-bpf add $sys$devpath /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o" +ACTION=="remove",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095A", RUN{program}+="/usr/local/bin/udev-hid-bpf remove $sys$devpath " +# xppen-ArtistPro16Gen2.bpf.o +ACTION=="add",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095B", RUN{program}+="/usr/local/bin/udev-hid-bpf add $sys$devpath /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o" +ACTION=="remove",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095B", RUN{program}+="/usr/local/bin/udev-hid-bpf remove $sys$devpath " + +LABEL="hid_bpf_end" +EOF +$> udevadm control --reload +``` + +Then unplug and replug the device. + +## Checks + +### udev rule + +You can check that the udev rule is correctly working by issuing + +``` +$> udevadm test /sys/bus/hid/devices/0003:28BD:095B* +... +run: '/usr/local/bin/udev-hid-bpf add /sys/devices/virtual/misc/uhid/0003:28BD:095B.0E57 /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o' +``` + +### program loaded + +You can check that the program has been properly loaded with `bpftool` + +``` +$> bpftool prog +... +247: tracing name xppen_16_fix_eraser tag 18d389353ed2ef07 gpl + loaded_at 2024-03-28T16:02:28+0100 uid 0 + xlated 120B jited 77B memlock 4096B + btf_id 487 +``` diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c new file mode 100644 index 000000000000..e1be6a12bb75 --- /dev/null +++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */ +#define PID_ARTIST_24 0x093A +#define PID_ARTIST_24_PRO 0x092D + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_24), + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_24_PRO) +); + +/* + * We need to amend the report descriptor for the following: + * - the device reports Eraser instead of using Secondary Barrel Switch + * - the pen doesn't have a rubber tail, so basically we are removing any + * eraser/invert bits + */ +static const __u8 fixed_rdesc[] = { + 0x05, 0x0d, // Usage Page (Digitizers) 0 + 0x09, 0x02, // Usage (Pen) 2 + 0xa1, 0x01, // Collection (Application) 4 + 0x85, 0x07, // Report ID (7) 6 + 0x09, 0x20, // Usage (Stylus) 8 + 0xa1, 0x00, // Collection (Physical) 10 + 0x09, 0x42, // Usage (Tip Switch) 12 + 0x09, 0x44, // Usage (Barrel Switch) 14 + 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from 0x45 (Eraser) to 0x5a (Secondary Barrel Switch) */ + 0x15, 0x00, // Logical Minimum (0) 18 + 0x25, 0x01, // Logical Maximum (1) 20 + 0x75, 0x01, // Report Size (1) 22 + 0x95, 0x03, // Report Count (3) 24 + 0x81, 0x02, // Input (Data,Var,Abs) 26 + 0x95, 0x02, // Report Count (2) 28 + 0x81, 0x03, // Input (Cnst,Var,Abs) 30 + 0x09, 0x32, // Usage (In Range) 32 + 0x95, 0x01, // Report Count (1) 34 + 0x81, 0x02, // Input (Data,Var,Abs) 36 + 0x95, 0x02, // Report Count (2) 38 + 0x81, 0x03, // Input (Cnst,Var,Abs) 40 + 0x75, 0x10, // Report Size (16) 42 + 0x95, 0x01, // Report Count (1) 44 + 0x35, 0x00, // Physical Minimum (0) 46 + 0xa4, // Push 48 + 0x05, 0x01, // Usage Page (Generic Desktop) 49 + 0x09, 0x30, // Usage (X) 51 + 0x65, 0x13, // Unit (EnglishLinear: in) 53 + 0x55, 0x0d, // Unit Exponent (-3) 55 + 0x46, 0xf0, 0x50, // Physical Maximum (20720) 57 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 60 + 0x81, 0x02, // Input (Data,Var,Abs) 63 + 0x09, 0x31, // Usage (Y) 65 + 0x46, 0x91, 0x2d, // Physical Maximum (11665) 67 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 70 + 0x81, 0x02, // Input (Data,Var,Abs) 73 + 0xb4, // Pop 75 + 0x09, 0x30, // Usage (Tip Pressure) 76 + 0x45, 0x00, // Physical Maximum (0) 78 + 0x26, 0xff, 0x1f, // Logical Maximum (8191) 80 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 83 + 0x09, 0x3d, // Usage (X Tilt) 85 + 0x15, 0x81, // Logical Minimum (-127) 87 + 0x25, 0x7f, // Logical Maximum (127) 89 + 0x75, 0x08, // Report Size (8) 91 + 0x95, 0x01, // Report Count (1) 93 + 0x81, 0x02, // Input (Data,Var,Abs) 95 + 0x09, 0x3e, // Usage (Y Tilt) 97 + 0x15, 0x81, // Logical Minimum (-127) 99 + 0x25, 0x7f, // Logical Maximum (127) 101 + 0x81, 0x02, // Input (Data,Var,Abs) 103 + 0xc0, // End Collection 105 + 0xc0, // End Collection 106 +}; + +#define BIT(n) (1UL << n) + +#define TIP_SWITCH BIT(0) +#define BARREL_SWITCH BIT(1) +#define ERASER BIT(2) +/* padding BIT(3) */ +/* padding BIT(4) */ +#define IN_RANGE BIT(5) +/* padding BIT(6) */ +/* padding BIT(7) */ + +#define U16(index) (data[index] | (data[index + 1] << 8)) + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc_xppen_artist24, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); + + if (!data) + return 0; /* EPERM check */ + + __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); + + return sizeof(fixed_rdesc); +} + +static __u8 prev_state = 0; + +/* + * There are a few cases where the device is sending wrong event + * sequences, all related to the second button (the pen doesn't + * have an eraser switch on the tail end): + * + * whenever the second button gets pressed or released, an + * out-of-proximity event is generated and then the firmware + * compensate for the missing state (and the firmware uses + * eraser for that button): + * + * - if the pen is in range, an extra out-of-range is sent + * when the second button is pressed/released: + * // Pen is in range + * E: InRange + * + * // Second button is pressed + * E: + * E: Eraser InRange + * + * // Second button is released + * E: + * E: InRange + * + * This case is ignored by this filter, it's "valid" + * and userspace knows how to deal with it, there are just + * a few out-of-prox events generated, but the user doesn´t + * see them. + * + * - if the pen is in contact, 2 extra events are added when + * the second button is pressed/released: an out of range + * and an in range: + * + * // Pen is in contact + * E: TipSwitch InRange + * + * // Second button is pressed + * E: <- false release, needs to be filtered out + * E: Eraser InRange <- false release, needs to be filtered out + * E: TipSwitch Eraser InRange + * + * // Second button is released + * E: <- false release, needs to be filtered out + * E: InRange <- false release, needs to be filtered out + * E: TipSwitch InRange + * + */ +SEC("fmod_ret/hid_bpf_device_event") +int BPF_PROG(xppen_24_fix_eraser, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); + __u8 current_state, changed_state; + bool prev_tip; + __u16 tilt; + + if (!data) + return 0; /* EPERM check */ + + current_state = data[1]; + + /* if the state is identical to previously, early return */ + if (current_state == prev_state) + return 0; + + prev_tip = !!(prev_state & TIP_SWITCH); + + /* + * Illegal transition: pen is in range with the tip pressed, and + * it goes into out of proximity. + * + * Ideally we should hold the event, start a timer and deliver it + * only if the timer ends, but we are not capable of that now. + * + * And it doesn't matter because when we are in such cases, this + * means we are detecting a false release. + */ + if ((current_state & IN_RANGE) == 0) { + if (prev_tip) + return HID_IGNORE_EVENT; + return 0; + } + + /* + * XOR to only set the bits that have changed between + * previous and current state + */ + changed_state = prev_state ^ current_state; + + /* Store the new state for future processing */ + prev_state = current_state; + + /* + * We get both a tipswitch and eraser change in the same HID report: + * this is not an authorized transition and is unlikely to happen + * in real life. + * This is likely to be added by the firmware to emulate the + * eraser mode so we can skip the event. + */ + if ((changed_state & (TIP_SWITCH | ERASER)) == (TIP_SWITCH | ERASER)) /* we get both a tipswitch and eraser change at the same time */ + return HID_IGNORE_EVENT; + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + /* + * The device exports 3 interfaces. + */ + ctx->retval = ctx->rdesc_size != 107; + if (ctx->retval) + ctx->retval = -EINVAL; + + /* ensure the kernel isn't fixed already */ + if (ctx->rdesc[17] != 0x45) /* Eraser */ + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/drivers/hid/bpf/progs/hid_bpf.h b/drivers/hid/bpf/progs/hid_bpf.h new file mode 100644 index 000000000000..7ee371cac2e1 --- /dev/null +++ b/drivers/hid/bpf/progs/hid_bpf.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2022 Benjamin Tissoires + */ + +#ifndef ____HID_BPF__H +#define ____HID_BPF__H + +struct hid_bpf_probe_args { + unsigned int hid; + unsigned int rdesc_size; + unsigned char rdesc[4096]; + int retval; +}; + +#endif /* ____HID_BPF__H */ diff --git a/drivers/hid/bpf/progs/hid_bpf_helpers.h b/drivers/hid/bpf/progs/hid_bpf_helpers.h new file mode 100644 index 000000000000..8f226f6e886b --- /dev/null +++ b/drivers/hid/bpf/progs/hid_bpf_helpers.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2022 Benjamin Tissoires + */ + +#ifndef __HID_BPF_HELPERS_H +#define __HID_BPF_HELPERS_H + +#include "vmlinux.h" +#include +#include + +extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, + unsigned int offset, + const size_t __sz) __ksym; +extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym; +extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; +extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, + __u8 *data, + size_t buf__sz, + enum hid_report_type type, + enum hid_class_request reqtype) __ksym; + +#define HID_MAX_DESCRIPTOR_SIZE 4096 +#define HID_IGNORE_EVENT -1 + +/* extracted from */ +#define BUS_ANY 0x00 +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define BUS_RMI 0x1D +#define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F +#define BUS_AMD_SFH 0x20 + +/* extracted from */ +#define HID_GROUP_ANY 0x0000 +#define HID_GROUP_GENERIC 0x0001 +#define HID_GROUP_MULTITOUCH 0x0002 +#define HID_GROUP_SENSOR_HUB 0x0003 +#define HID_GROUP_MULTITOUCH_WIN_8 0x0004 +#define HID_GROUP_RMI 0x0100 +#define HID_GROUP_WACOM 0x0101 +#define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102 +#define HID_GROUP_STEAM 0x0103 +#define HID_GROUP_LOGITECH_27MHZ_DEVICE 0x0104 +#define HID_GROUP_VIVALDI 0x0105 + +/* include/linux/mod_devicetable.h defines as (~0), but that gives us negative size arrays */ +#define HID_VID_ANY 0x0000 +#define HID_PID_ANY 0x0000 + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* Helper macro to convert (foo, __LINE__) into foo134 so we can use __LINE__ for + * field/variable names + */ +#define COMBINE1(X, Y) X ## Y +#define COMBINE(X, Y) COMBINE1(X, Y) + +/* Macro magic: + * __uint(foo, 123) creates a int (*foo)[1234] + * + * We use that macro to declare an anonymous struct with several + * fields, each is the declaration of an pointer to an array of size + * bus/group/vid/pid. (Because it's a pointer to such an array, actual storage + * would be sizeof(pointer) rather than sizeof(array). Not that we ever + * instantiate it anyway). + * + * This is only used for BTF introspection, we can later check "what size + * is the bus array" in the introspection data and thus extract the bus ID + * again. + * + * And we use the __LINE__ to give each of our structs a unique name so the + * BPF program writer doesn't have to. + * + * $ bpftool btf dump file target/bpf/HP_Elite_Presenter.bpf.o + * shows the inspection data, start by searching for .hid_bpf_config + * and working backwards from that (each entry references the type_id of the + * content). + */ + +#define HID_DEVICE(b, g, ven, prod) \ + struct { \ + __uint(name, 0); \ + __uint(bus, (b)); \ + __uint(group, (g)); \ + __uint(vid, (ven)); \ + __uint(pid, (prod)); \ + } COMBINE(_entry, __LINE__) + +/* Macro magic below is to make HID_BPF_CONFIG() look like a function call that + * we can pass multiple HID_DEVICE() invocations in. + * + * For up to 16 arguments, HID_BPF_CONFIG(one, two) resolves to + * + * union { + * HID_DEVICE(...); + * HID_DEVICE(...); + * } _device_ids SEC(".hid_bpf_config") + * + */ + +/* Returns the number of macro arguments, this expands + * NARGS(a, b, c) to NTH_ARG(a, b, c, 15, 14, 13, .... 4, 3, 2, 1). + * NTH_ARG always returns the 16th argument which in our case is 3. + * + * If we want more than 16 values _COUNTDOWN and _NTH_ARG both need to be + * updated. + */ +#define _NARGS(...) _NARGS1(__VA_ARGS__, _COUNTDOWN) +#define _NARGS1(...) _NTH_ARG(__VA_ARGS__) + +/* Add to this if we need more than 16 args */ +#define _COUNTDOWN \ + 15, 14, 13, 12, 11, 10, 9, 8, \ + 7, 6, 5, 4, 3, 2, 1, 0 + +/* Return the 16 argument passed in. See _NARGS above for usage. Note this is + * 1-indexed. + */ +#define _NTH_ARG( \ + _1, _2, _3, _4, _5, _6, _7, _8, \ + _9, _10, _11, _12, _13, _14, _15,\ + N, ...) N + +/* Turns EXPAND(_ARG, a, b, c) into _ARG3(a, b, c) */ +#define _EXPAND(func, ...) COMBINE(func, _NARGS(__VA_ARGS__)) (__VA_ARGS__) + +/* And now define all the ARG macros for each number of args we want to accept */ +#define _ARG1(_1) _1; +#define _ARG2(_1, _2) _1; _2; +#define _ARG3(_1, _2, _3) _1; _2; _3; +#define _ARG4(_1, _2, _3, _4) _1; _2; _3; _4; +#define _ARG5(_1, _2, _3, _4, _5) _1; _2; _3; _4; _5; +#define _ARG6(_1, _2, _3, _4, _5, _6) _1; _2; _3; _4; _5; _6; +#define _ARG7(_1, _2, _3, _4, _5, _6, _7) _1; _2; _3; _4; _5; _6; _7; +#define _ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _1; _2; _3; _4; _5; _6; _7; _8; +#define _ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1; _2; _3; _4; _5; _6; _7; _8; _9; +#define _ARG10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; +#define _ARG11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; +#define _ARG12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; +#define _ARG13(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d; +#define _ARG14(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d, _e) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d; _e; +#define _ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d, _e, _f) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d; _e; _f; + + +#define HID_BPF_CONFIG(...) union { \ + _EXPAND(_ARG, __VA_ARGS__) \ +} _device_ids SEC(".hid_bpf_config") + +#endif /* __HID_BPF_HELPERS_H */ -- cgit v1.2.3 From e0599675a32cb994a076a4b40d3e42d8353a5bb7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:23 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the XPPen Artist 16 Same problem than the Artist 24: the second button on the pen is treated like an eraser. But the problem is even worse this time. There is an actual eraser at the tail of the pen. The compensation of the coordinates was done by Martin Signed-off-by: Martin Sivak Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-3-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c | 274 +++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c new file mode 100644 index 000000000000..65ef10036126 --- /dev/null +++ b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */ +#define PID_ARTIST_PRO14_GEN2 0x095A +#define PID_ARTIST_PRO16_GEN2 0x095B + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO14_GEN2), + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO16_GEN2) +); + +/* + * We need to amend the report descriptor for the following: + * - the device reports Eraser instead of using Secondary Barrel Switch + * - when the eraser button is pressed and the stylus is touching the tablet, + * the device sends Tip Switch instead of sending Eraser + * + * This descriptor uses physical dimensions of the 16" device. + */ +static const __u8 fixed_rdesc[] = { + 0x05, 0x0d, // Usage Page (Digitizers) 0 + 0x09, 0x02, // Usage (Pen) 2 + 0xa1, 0x01, // Collection (Application) 4 + 0x85, 0x07, // Report ID (7) 6 + 0x09, 0x20, // Usage (Stylus) 8 + 0xa1, 0x00, // Collection (Physical) 10 + 0x09, 0x42, // Usage (Tip Switch) 12 + 0x09, 0x44, // Usage (Barrel Switch) 14 + 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from 0x45 (Eraser) to 0x5a (Secondary Barrel Switch) */ + 0x09, 0x3c, // Usage (Invert) 18 + 0x09, 0x45, // Usage (Eraser) 16 /* created over a padding bit at offset 29-33 */ + 0x15, 0x00, // Logical Minimum (0) 20 + 0x25, 0x01, // Logical Maximum (1) 22 + 0x75, 0x01, // Report Size (1) 24 + 0x95, 0x05, // Report Count (5) 26 /* changed from 4 to 5 */ + 0x81, 0x02, // Input (Data,Var,Abs) 28 + 0x09, 0x32, // Usage (In Range) 34 + 0x15, 0x00, // Logical Minimum (0) 36 + 0x25, 0x01, // Logical Maximum (1) 38 + 0x95, 0x01, // Report Count (1) 40 + 0x81, 0x02, // Input (Data,Var,Abs) 42 + 0x95, 0x02, // Report Count (2) 44 + 0x81, 0x03, // Input (Cnst,Var,Abs) 46 + 0x75, 0x10, // Report Size (16) 48 + 0x95, 0x01, // Report Count (1) 50 + 0x35, 0x00, // Physical Minimum (0) 52 + 0xa4, // Push 54 + 0x05, 0x01, // Usage Page (Generic Desktop) 55 + 0x09, 0x30, // Usage (X) 57 + 0x65, 0x13, // Unit (EnglishLinear: in) 59 + 0x55, 0x0d, // Unit Exponent (-3) 61 + 0x46, 0xff, 0x34, // Physical Maximum (13567) 63 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 66 + 0x81, 0x02, // Input (Data,Var,Abs) 69 + 0x09, 0x31, // Usage (Y) 71 + 0x46, 0x20, 0x21, // Physical Maximum (8480) 73 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 76 + 0x81, 0x02, // Input (Data,Var,Abs) 79 + 0xb4, // Pop 81 + 0x09, 0x30, // Usage (Tip Pressure) 82 + 0x45, 0x00, // Physical Maximum (0) 84 + 0x26, 0xff, 0x3f, // Logical Maximum (16383) 86 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 89 + 0x09, 0x3d, // Usage (X Tilt) 91 + 0x15, 0x81, // Logical Minimum (-127) 93 + 0x25, 0x7f, // Logical Maximum (127) 95 + 0x75, 0x08, // Report Size (8) 97 + 0x95, 0x01, // Report Count (1) 99 + 0x81, 0x02, // Input (Data,Var,Abs) 101 + 0x09, 0x3e, // Usage (Y Tilt) 103 + 0x15, 0x81, // Logical Minimum (-127) 105 + 0x25, 0x7f, // Logical Maximum (127) 107 + 0x81, 0x02, // Input (Data,Var,Abs) 109 + 0xc0, // End Collection 111 + 0xc0, // End Collection 112 +}; + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc_xppen_artistpro16gen2, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); + + if (!data) + return 0; /* EPERM check */ + + __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); + + /* Fix the Physical maximum values for different sizes of the device + * The 14" screen device descriptor size is 11.874" x 7.421" + */ + if (hctx->hid->product == PID_ARTIST_PRO14_GEN2) { + data[63] = 0x2e; + data[62] = 0x62; + data[73] = 0x1c; + data[72] = 0xfd; + } + + return sizeof(fixed_rdesc); +} + +SEC("fmod_ret/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 */); + + if (!data) + return 0; /* EPERM check */ + + if ((data[1] & 0x29) != 0x29) /* tip switch=1 invert=1 inrange=1 */ + return 0; + + /* xor bits 0,3 and 4: convert Tip Switch + Invert into Eraser only */ + data[1] ^= 0x19; + + return 0; +} + +/* + * Static coordinate offset table based on positive only angles + * Two tables are needed, because the logical coordinates are scaled + * + * The table can be generated by Python like this: + * >>> full_scale = 11.874 # the display width/height in inches + * >>> tip_height = 0.055677699 # the center of the pen coil distance from screen in inch (empirical) + * >>> h = tip_height * (32767 / full_scale) # height of the coil in logical coordinates + * >>> [round(h*math.sin(math.radians(d))) for d in range(0, 128)] + * [0, 13, 26, ....] + */ + +/* 14" inch screen 11.874" x 7.421" */ +static const __u16 angle_offsets_horizontal_14[128] = { + 0, 3, 5, 8, 11, 13, 16, 19, 21, 24, 27, 29, 32, 35, 37, 40, 42, 45, 47, 50, 53, + 55, 58, 60, 62, 65, 67, 70, 72, 74, 77, 79, 81, 84, 86, 88, 90, 92, 95, 97, 99, + 101, 103, 105, 107, 109, 111, 112, 114, 116, 118, 119, 121, 123, 124, 126, 127, + 129, 130, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 148, 149, 150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 153, 154, + 154, 154, 154, 154, 153, 153, 153, 153, 153, 152, 152, 151, 151, 150, 150, 149, + 148, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 134, 133, + 132, 130, 129, 127, 126, 124, 123 +}; +static const __u16 angle_offsets_vertical_14[128] = { + 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 59, 64, 68, 72, 76, 80, 84, + 88, 92, 96, 100, 104, 108, 112, 115, 119, 123, 127, 130, 134, 137, 141, 145, 148, + 151, 155, 158, 161, 165, 168, 171, 174, 177, 180, 183, 186, 188, 191, 194, 196, + 199, 201, 204, 206, 208, 211, 213, 215, 217, 219, 221, 223, 225, 226, 228, 230, + 231, 232, 234, 235, 236, 237, 239, 240, 240, 241, 242, 243, 243, 244, 244, 245, + 245, 246, 246, 246, 246, 246, 246, 246, 245, 245, 244, 244, 243, 243, 242, 241, + 240, 240, 239, 237, 236, 235, 234, 232, 231, 230, 228, 226, 225, 223, 221, 219, + 217, 215, 213, 211, 208, 206, 204, 201, 199, 196 +}; + +/* 16" inch screen 13.567" x 8.480" */ +static const __u16 angle_offsets_horizontal_16[128] = { + 0, 2, 5, 7, 9, 12, 14, 16, 19, 21, 23, 26, 28, 30, 33, 35, 37, 39, 42, 44, 46, 48, + 50, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, + 92, 93, 95, 97, 98, 100, 101, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, + 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, + 130, 131, 132, 132, 132, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 133, 133, 133, 132, 132, 132, 131, 130, 130, 129, 129, + 128, 127, 126, 126, 125, 124, 123, 122, 121, 120, 119, 118, 116, 115, 114, 113, + 111, 110, 109, 107 +}; +static const __u16 angle_offsets_vertical_16[128] = { + 0, 4, 8, 11, 15, 19, 22, 26, 30, 34, 37, 41, 45, 48, 52, 56, 59, 63, 66, 70, 74, + 77, 81, 84, 88, 91, 94, 98, 101, 104, 108, 111, 114, 117, 120, 123, 126, 129, 132, + 135, 138, 141, 144, 147, 149, 152, 155, 157, 160, 162, 165, 167, 170, 172, 174, + 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 198, 199, 201, 202, + 203, 205, 206, 207, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 214, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 214, 214, 214, 213, 212, 212, 211, 210, + 210, 209, 208, 207, 206, 205, 203, 202, 201, 199, 198, 197, 195, 193, 192, 190, + 188, 186, 184, 182, 180, 178, 176, 174, 172 +}; + +static void compensate_coordinates_by_tilt(__u8 *data, const __u8 idx, + const __s8 tilt, const __u16 (*compensation_table)[128]) +{ + __u16 coords = data[idx+1]; + + coords <<= 8; + coords += data[idx]; + + __u8 direction = tilt > 0 ? 0 : 1; /* Positive tilt means we need to subtract the compensation (vs. negative angle where we need to add) */ + __u8 angle = tilt > 0 ? tilt : -tilt; + + if (angle > 127) + return; + + __u16 compensation = (*compensation_table)[angle]; + + if (direction == 0) { + coords = (coords > compensation) ? coords - compensation : 0; + } else { + const __u16 logical_maximum = 32767; + __u16 max = logical_maximum - compensation; + + coords = (coords < max) ? coords + compensation : logical_maximum; + } + + data[idx] = coords & 0xff; + data[idx+1] = coords >> 8; +} + +SEC("fmod_ret/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 */); + + if (!data) + return 0; /* EPERM check */ + + /* + * Compensate X and Y offset caused by tilt. + * + * The magnetic center moves when the pen is tilted, because the coil + * is not touching the screen. + * + * a (tilt angle) + * | /... h (coil distance from tip) + * | / + * |/______ + * |x (position offset) + * + * x = sin a * h + * + * Subtract the offset from the coordinates. Use the precomputed table! + * + * bytes 0 - report id + * 1 - buttons + * 2-3 - X coords (logical) + * 4-5 - Y coords + * 6-7 - pressure (ignore) + * 8 - tilt X + * 9 - tilt Y + */ + + __s8 tilt_x = (__s8) data[8]; + __s8 tilt_y = (__s8) data[9]; + + if (hctx->hid->product == PID_ARTIST_PRO14_GEN2) { + compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_14); + compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_14); + } else if (hctx->hid->product == PID_ARTIST_PRO16_GEN2) { + compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_16); + compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_16); + } + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + /* + * The device exports 3 interfaces. + */ + ctx->retval = ctx->rdesc_size != 113; + if (ctx->retval) + ctx->retval = -EINVAL; + + /* ensure the kernel isn't fixed already */ + if (ctx->rdesc[17] != 0x45) /* Eraser */ + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 4e6d2a297dd5be26ad409b7a05b20bd033d1c95e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:24 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the HP Elite Presenter Mouse Duplicate of commit 0db117359e47 ("HID: add quirk for 03f0:464a HP Elite Presenter Mouse"), but in a slightly better way. This time we actually change the application collection, making clearer for userspace what the second mouse is. Note that having both hid-quirks fix and this HID-BPF fix is not a problem at all. Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-4-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c new file mode 100644 index 000000000000..3d14bbb6f276 --- /dev/null +++ b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_HP 0x03F0 +#define PID_ELITE_PRESENTER 0x464A + +HID_BPF_CONFIG( + HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HP, PID_ELITE_PRESENTER) +); + +/* + * Already fixed as of commit 0db117359e47 ("HID: add quirk for 03f0:464a + * HP Elite Presenter Mouse") in the kernel, but this is a slightly better + * fix. + * + * The HP Elite Presenter Mouse HID Record Descriptor shows + * two mice (Report ID 0x1 and 0x2), one keypad (Report ID 0x5), + * two Consumer Controls (Report IDs 0x6 and 0x3). + * Prior to these fixes it registers one mouse, one keypad + * and one Consumer Control, and it was usable only as a + * digital laser pointer (one of the two mouses). + * We replace the second mouse collection with a pointer collection, + * allowing to use the device both as a mouse and a digital laser + * pointer. + */ + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); + + if (!data) + return 0; /* EPERM check */ + + /* replace application mouse by application pointer on the second collection */ + if (data[79] == 0x02) + data[79] = 0x01; + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + ctx->retval = ctx->rdesc_size != 264; + if (ctx->retval) + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 0bc8f89f40403cfbc3c6e676b0bee240a9349d3f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:25 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the IOGear Kaliber Gaming MMOmentum mouse Allows to export more than 5 buttons on this 12 buttons mouse. Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-5-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- .../hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c new file mode 100644 index 000000000000..225cbefdbf0e --- /dev/null +++ b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_IOGEAR 0x258A /* VID is shared with SinoWealth and Glorious and prob others */ +#define PID_MOMENTUM 0x0027 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_IOGEAR, PID_MOMENTUM) +); + +/* + * The IOGear Kaliber Gaming MMOmentum Pro mouse has multiple buttons (12) + * but only 5 are accessible out of the box because the report descriptor + * marks the other buttons as constants. + * We just fix the report descriptor to enable those missing 7 buttons. + */ + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) +{ + const u8 offsets[] = {84, 112, 140}; + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); + + if (!data) + return 0; /* EPERM check */ + + /* if not Keyboard */ + if (data[3] != 0x06) + return 0; + + for (int idx = 0; idx < ARRAY_SIZE(offsets); idx++) { + u8 offset = offsets[idx]; + + /* if Input (Cnst,Var,Abs) , make it Input (Data,Var,Abs) */ + if (data[offset] == 0x81 && data[offset + 1] == 0x03) + data[offset + 1] = 0x02; + } + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + /* only bind to the keyboard interface */ + ctx->retval = ctx->rdesc_size != 213; + if (ctx->retval) + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From d9e78973921d215a6453b609a6326dab9dbc5a60 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:26 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the Wacom ArtPen This pen is compatible with multiple Wacom tablets, but we only add support for the Intuos Pro 2 M, as this is the one our user reported the bug against. We can not generically add all compatible Wacom tablets as we are writing the offsets by hand. The point of this HID-BPF program is to work around a firmware limitation where the pressure is repeated every other report. Given that we know this will happen, we can change the first new pressure information with the mean compared to the previous one. This way we smooth the incoming pressure without losing information. Cc: Ping Cheng Cc: Jason Gerecke Cc: Aaron Armstrong Skomra Cc: Joshua Dickens Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-6-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c | 173 ++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c new file mode 100644 index 000000000000..dc05aa48faa7 --- /dev/null +++ b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_WACOM 0x056a +#define ART_PEN_ID 0x0804 +#define PID_INTUOS_PRO_2_M 0x0357 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_WACOM, PID_INTUOS_PRO_2_M) +); + +/* + * This filter is here for the Art Pen stylus only: + * - when used on some Wacom devices (see the list of attached PIDs), this pen + * reports pressure every other events. + * - to solve that, given that we know that the next event will be the same as + * the current one, we can emulate a smoother pressure reporting by reporting + * the mean of the previous value and the current one. + * + * We are effectively delaying the pressure by one event every other event, but + * that's less of an annoyance compared to the chunkiness of the reported data. + * + * For example, let's assume the following set of events: + * + * + * + * + * + * + * + * The filter will report: + * + * + * + * + * + * + * + */ + +struct wacom_params { + __u16 pid; + __u16 rdesc_len; + __u8 report_id; + __u8 report_len; + struct { + __u8 tip_switch; + __u8 pressure; + __u8 tool_type; + } offsets; +}; + +/* + * Multiple device can support the same stylus, so + * we need to know which device has which offsets + */ +static const struct wacom_params devices[] = { + { + .pid = PID_INTUOS_PRO_2_M, + .rdesc_len = 949, + .report_id = 16, + .report_len = 27, + .offsets = { + .tip_switch = 1, + .pressure = 8, + .tool_type = 25, + }, + }, +}; + +static struct wacom_params params = { 0 }; + +/* HID-BPF reports a 64 bytes chunk anyway, so this ensures + * the verifier to know we are addressing the memory correctly + */ +#define PEN_REPORT_LEN 64 + +/* only odd frames are modified */ +static bool odd; + +static __u16 prev_pressure; + +static inline void *get_bits(__u8 *data, unsigned int byte_offset) +{ + return data + byte_offset; +} + +static inline __u16 *get_u16(__u8 *data, unsigned int offset) +{ + return (__u16 *)get_bits(data, offset); +} + +static inline __u8 *get_u8(__u8 *data, unsigned int offset) +{ + return (__u8 *)get_bits(data, offset); +} + +SEC("fmod_ret/hid_bpf_device_event") +int BPF_PROG(artpen_pressure_interpolate, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PEN_REPORT_LEN /* size */); + __u16 *pressure, *tool_type; + __u8 *tip_switch; + + if (!data) + return 0; /* EPERM check */ + + if (data[0] != params.report_id || + params.offsets.tip_switch >= PEN_REPORT_LEN || + params.offsets.pressure >= PEN_REPORT_LEN - 1 || + params.offsets.tool_type >= PEN_REPORT_LEN - 1) + return 0; /* invalid report or parameters */ + + tool_type = get_u16(data, params.offsets.tool_type); + if (*tool_type != ART_PEN_ID) + return 0; + + tip_switch = get_u8(data, params.offsets.tip_switch); + if ((*tip_switch & 0x01) == 0) { + prev_pressure = 0; + odd = true; + return 0; + } + + pressure = get_u16(data, params.offsets.pressure); + + if (odd) + *pressure = (*pressure + prev_pressure) / 2; + + prev_pressure = *pressure; + odd = !odd; + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + struct hid_bpf_ctx *hid_ctx; + __u16 pid; + int i; + + /* get a struct hid_device to access the actual pid of the device */ + hid_ctx = hid_bpf_allocate_context(ctx->hid); + if (!hid_ctx) { + ctx->retval = -ENODEV; + return -1; /* EPERM check */ + } + pid = hid_ctx->hid->product; + + ctx->retval = -EINVAL; + + /* Match the given device with the list of known devices */ + for (i = 0; i < ARRAY_SIZE(devices); i++) { + const struct wacom_params *device = &devices[i]; + + if (device->pid == pid && device->rdesc_len == ctx->rdesc_size) { + params = *device; + ctx->retval = 0; + } + } + + hid_bpf_release_context(hid_ctx); + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 1c046d09c6ba4ff5fb959b2d195cacadb2ae6977 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:27 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the XBox Elite 2 over Bluetooth When using the XBox Wireless Controller Elite 2 over Bluetooth, the device exports the paddle 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. SDL doesn't know how to interprete that 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 Consumer Control one) - we need to change the usage to be buttons from 0x15 to 0x18 Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-7-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- .../hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c new file mode 100644 index 000000000000..c04abecab8ee --- /dev/null +++ b/drivers/hid/bpf/progs/Microsoft__XBox-Elite-2.bpf.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_MICROSOFT 0x045e +#define PID_XBOX_ELITE_2 0x0b22 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_MICROSOFT, PID_XBOX_ELITE_2) +); + +/* + * When using the XBox Wireless Controller Elite 2 over Bluetooth, + * the device exports the paddle 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. + * + * SDL doesn't know how to interprete that 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 + * Consumer Control one) + * - we need to change the usage to be buttons from 0x15 to 0x18 + */ + +#define OFFSET_ASSIGN_SELECTION 211 +#define ORIGINAL_RDESC_SIZE 464 + +const __u8 rdesc_assign_selection[] = { + 0x0a, 0x99, 0x00, // Usage (Media Select Security) 211 + 0x15, 0x00, // Logical Minimum (0) 214 + 0x26, 0xff, 0x00, // Logical Maximum (255) 216 + 0x95, 0x01, // Report Count (1) 219 + 0x75, 0x04, // Report Size (4) 221 + 0x81, 0x02, // Input (Data,Var,Abs) 223 + 0x15, 0x00, // Logical Minimum (0) 225 + 0x25, 0x00, // Logical Maximum (0) 227 + 0x95, 0x01, // Report Count (1) 229 + 0x75, 0x04, // Report Size (4) 231 + 0x81, 0x03, // Input (Cnst,Var,Abs) 233 + 0x0a, 0x81, 0x00, // Usage (Assign Selection) 235 + 0x15, 0x00, // Logical Minimum (0) 238 + 0x26, 0xff, 0x00, // Logical Maximum (255) 240 + 0x95, 0x01, // Report Count (1) 243 + 0x75, 0x04, // Report Size (4) 245 + 0x81, 0x02, // Input (Data,Var,Abs) 247 +}; + +/* + * we replace the above report descriptor extract + * with the one below. + * To make things equal in size, we take out a larger + * portion than just the "Assign Selection" range, because + * we need to insert a new application collection to force + * the kernel to use BTN_TRIGGER_HAPPY[4-7]. + */ +const __u8 fixed_rdesc_assign_selection[] = { + 0x0a, 0x99, 0x00, // Usage (Media Select Security) 211 + 0x15, 0x00, // Logical Minimum (0) 214 + 0x26, 0xff, 0x00, // Logical Maximum (255) 216 + 0x95, 0x01, // Report Count (1) 219 + 0x75, 0x04, // Report Size (4) 221 + 0x81, 0x02, // Input (Data,Var,Abs) 223 + /* 0x15, 0x00, */ // Logical Minimum (0) ignored + 0x25, 0x01, // Logical Maximum (1) 225 + 0x95, 0x04, // Report Count (4) 227 + 0x75, 0x01, // Report Size (1) 229 + 0x81, 0x03, // Input (Cnst,Var,Abs) 231 + 0xc0, // End Collection 233 + 0x05, 0x01, // Usage Page (Generic Desktop) 234 + 0x0a, 0x05, 0x00, // Usage (Game Pad) 236 + 0xa1, 0x01, // Collection (Application) 239 + 0x05, 0x09, // Usage Page (Button) 241 + 0x19, 0x15, // Usage Minimum (21) 243 + 0x29, 0x18, // Usage Maximum (24) 245 + /* 0x15, 0x00, */ // Logical Minimum (0) ignored + /* 0x25, 0x01, */ // Logical Maximum (1) ignored + /* 0x95, 0x01, */ // Report Size (1) ignored + /* 0x75, 0x04, */ // Report Count (4) ignored + 0x81, 0x02, // Input (Data,Var,Abs) 247 +}; + +_Static_assert(sizeof(rdesc_assign_selection) == sizeof(fixed_rdesc_assign_selection), + "Rdesc and fixed rdesc of different size"); +_Static_assert(sizeof(rdesc_assign_selection) + OFFSET_ASSIGN_SELECTION < ORIGINAL_RDESC_SIZE, + "Rdesc at given offset is too big"); + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); + + if (!data) + return 0; /* EPERM check */ + + /* Check that the device is compatible */ + if (__builtin_memcmp(data + OFFSET_ASSIGN_SELECTION, + rdesc_assign_selection, + sizeof(rdesc_assign_selection))) + return 0; + + __builtin_memcpy(data + OFFSET_ASSIGN_SELECTION, + fixed_rdesc_assign_selection, + sizeof(fixed_rdesc_assign_selection)); + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + /* only bind to the keyboard interface */ + ctx->retval = ctx->rdesc_size != ORIGINAL_RDESC_SIZE; + if (ctx->retval) + ctx->retval = -EINVAL; + + if (__builtin_memcmp(ctx->rdesc + OFFSET_ASSIGN_SELECTION, + rdesc_assign_selection, + sizeof(rdesc_assign_selection))) + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 9f1bf4c225329d27e85fc1c5b5af9e6ebf4a8ff3 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:28 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the Huion Kamvas Pro 19 This tablets gets a lot of things wrong: - the secondary button is reported through Secondary Tip Switch - the third button is reported through Invert Fortunately, before entering eraser mode, (so Invert = 1), the tablet always sends an out-of-proximity event. So we can detect that single event and: - if there was none but the invert bit was toggled: this is the third button - if there was this out-of-proximity event, we are entering eraser mode, and we will until the next out-of-proximity. Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-8-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c | 290 +++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c new file mode 100644 index 000000000000..ff759f2276f9 --- /dev/null +++ b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_HUION 0x256C +#define PID_KAMVAS_PRO_19 0x006B +#define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902" + +#define TEST_PREFIX "uhid test " + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19), +); + +bool prev_was_out_of_range; +bool in_eraser_mode; + +/* + * We need to amend the report descriptor for the following: + * - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch + * - the third button is reported through Invert, and we need some room to report it. + * + */ +static const __u8 fixed_rdesc[] = { + 0x05, 0x0d, // Usage Page (Digitizers) 0 + 0x09, 0x02, // Usage (Pen) 2 + 0xa1, 0x01, // Collection (Application) 4 + 0x85, 0x0a, // Report ID (10) 6 + 0x09, 0x20, // Usage (Stylus) 8 + 0xa1, 0x01, // Collection (Application) 10 + 0x09, 0x42, // Usage (Tip Switch) 12 + 0x09, 0x44, // Usage (Barrel Switch) 14 + 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */ + 0x09, 0x3c, // Usage (Invert) 18 + 0x09, 0x45, // Usage (Eraser) 20 + 0x15, 0x00, // Logical Minimum (0) 22 + 0x25, 0x01, // Logical Maximum (1) 24 + 0x75, 0x01, // Report Size (1) 26 + 0x95, 0x05, // Report Count (5) 28 /* changed (was 5) */ + 0x81, 0x02, // Input (Data,Var,Abs) 30 + 0x05, 0x09, // Usage Page (Button) /* inserted */ + 0x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */ + 0x95, 0x01, // Report Count (1) /* inserted */ + 0x81, 0x02, // Input (Data,Var,Abs) /* inserted */ + 0x05, 0x0d, // Usage Page (Digitizers) /* inserted */ + 0x09, 0x32, // Usage (In Range) 32 + 0x75, 0x01, // Report Size (1) 34 + 0x95, 0x01, // Report Count (1) 36 + 0x81, 0x02, // Input (Data,Var,Abs) 38 + 0x81, 0x03, // Input (Cnst,Var,Abs) 40 + 0x05, 0x01, // Usage Page (Generic Desktop) 42 + 0x09, 0x30, // Usage (X) 44 + 0x09, 0x31, // Usage (Y) 46 + 0x55, 0x0d, // Unit Exponent (-3) 48 + 0x65, 0x33, // Unit (EnglishLinear: in³) 50 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52 + 0x35, 0x00, // Physical Minimum (0) 55 + 0x46, 0x00, 0x08, // Physical Maximum (2048) 57 + 0x75, 0x10, // Report Size (16) 60 + 0x95, 0x02, // Report Count (2) 62 + 0x81, 0x02, // Input (Data,Var,Abs) 64 + 0x05, 0x0d, // Usage Page (Digitizers) 66 + 0x09, 0x30, // Usage (Tip Pressure) 68 + 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70 + 0x75, 0x10, // Report Size (16) 73 + 0x95, 0x01, // Report Count (1) 75 + 0x81, 0x02, // Input (Data,Var,Abs) 77 + 0x09, 0x3d, // Usage (X Tilt) 79 + 0x09, 0x3e, // Usage (Y Tilt) 81 + 0x15, 0xa6, // Logical Minimum (-90) 83 + 0x25, 0x5a, // Logical Maximum (90) 85 + 0x75, 0x08, // Report Size (8) 87 + 0x95, 0x02, // Report Count (2) 89 + 0x81, 0x02, // Input (Data,Var,Abs) 91 + 0xc0, // End Collection 93 + 0xc0, // End Collection 94 + 0x05, 0x0d, // Usage Page (Digitizers) 95 + 0x09, 0x04, // Usage (Touch Screen) 97 + 0xa1, 0x01, // Collection (Application) 99 + 0x85, 0x04, // Report ID (4) 101 + 0x09, 0x22, // Usage (Finger) 103 + 0xa1, 0x02, // Collection (Logical) 105 + 0x05, 0x0d, // Usage Page (Digitizers) 107 + 0x95, 0x01, // Report Count (1) 109 + 0x75, 0x06, // Report Size (6) 111 + 0x09, 0x51, // Usage (Contact Id) 113 + 0x15, 0x00, // Logical Minimum (0) 115 + 0x25, 0x3f, // Logical Maximum (63) 117 + 0x81, 0x02, // Input (Data,Var,Abs) 119 + 0x09, 0x42, // Usage (Tip Switch) 121 + 0x25, 0x01, // Logical Maximum (1) 123 + 0x75, 0x01, // Report Size (1) 125 + 0x95, 0x01, // Report Count (1) 127 + 0x81, 0x02, // Input (Data,Var,Abs) 129 + 0x75, 0x01, // Report Size (1) 131 + 0x95, 0x01, // Report Count (1) 133 + 0x81, 0x03, // Input (Cnst,Var,Abs) 135 + 0x05, 0x01, // Usage Page (Generic Desktop) 137 + 0x75, 0x10, // Report Size (16) 139 + 0x55, 0x0e, // Unit Exponent (-2) 141 + 0x65, 0x11, // Unit (SILinear: cm) 143 + 0x09, 0x30, // Usage (X) 145 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147 + 0x35, 0x00, // Physical Minimum (0) 150 + 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 155 + 0x09, 0x31, // Usage (Y) 157 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159 + 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 165 + 0x05, 0x0d, // Usage Page (Digitizers) 167 + 0x09, 0x30, // Usage (Tip Pressure) 169 + 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171 + 0x75, 0x10, // Report Size (16) 174 + 0x95, 0x01, // Report Count (1) 176 + 0x81, 0x02, // Input (Data,Var,Abs) 178 + 0xc0, // End Collection 180 + 0x05, 0x0d, // Usage Page (Digitizers) 181 + 0x09, 0x22, // Usage (Finger) 183 + 0xa1, 0x02, // Collection (Logical) 185 + 0x05, 0x0d, // Usage Page (Digitizers) 187 + 0x95, 0x01, // Report Count (1) 189 + 0x75, 0x06, // Report Size (6) 191 + 0x09, 0x51, // Usage (Contact Id) 193 + 0x15, 0x00, // Logical Minimum (0) 195 + 0x25, 0x3f, // Logical Maximum (63) 197 + 0x81, 0x02, // Input (Data,Var,Abs) 199 + 0x09, 0x42, // Usage (Tip Switch) 201 + 0x25, 0x01, // Logical Maximum (1) 203 + 0x75, 0x01, // Report Size (1) 205 + 0x95, 0x01, // Report Count (1) 207 + 0x81, 0x02, // Input (Data,Var,Abs) 209 + 0x75, 0x01, // Report Size (1) 211 + 0x95, 0x01, // Report Count (1) 213 + 0x81, 0x03, // Input (Cnst,Var,Abs) 215 + 0x05, 0x01, // Usage Page (Generic Desktop) 217 + 0x75, 0x10, // Report Size (16) 219 + 0x55, 0x0e, // Unit Exponent (-2) 221 + 0x65, 0x11, // Unit (SILinear: cm) 223 + 0x09, 0x30, // Usage (X) 225 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227 + 0x35, 0x00, // Physical Minimum (0) 230 + 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 235 + 0x09, 0x31, // Usage (Y) 237 + 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239 + 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242 + 0x81, 0x42, // Input (Data,Var,Abs,Null) 245 + 0x05, 0x0d, // Usage Page (Digitizers) 247 + 0x09, 0x30, // Usage (Tip Pressure) 249 + 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251 + 0x75, 0x10, // Report Size (16) 254 + 0x95, 0x01, // Report Count (1) 256 + 0x81, 0x02, // Input (Data,Var,Abs) 258 + 0xc0, // End Collection 260 + 0x05, 0x0d, // Usage Page (Digitizers) 261 + 0x09, 0x56, // Usage (Scan Time) 263 + 0x55, 0x00, // Unit Exponent (0) 265 + 0x65, 0x00, // Unit (None) 267 + 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269 + 0x95, 0x01, // Report Count (1) 274 + 0x75, 0x20, // Report Size (32) 276 + 0x81, 0x02, // Input (Data,Var,Abs) 278 + 0x09, 0x54, // Usage (Contact Count) 280 + 0x25, 0x7f, // Logical Maximum (127) 282 + 0x95, 0x01, // Report Count (1) 284 + 0x75, 0x08, // Report Size (8) 286 + 0x81, 0x02, // Input (Data,Var,Abs) 288 + 0x75, 0x08, // Report Size (8) 290 + 0x95, 0x08, // Report Count (8) 292 + 0x81, 0x03, // Input (Cnst,Var,Abs) 294 + 0x85, 0x05, // Report ID (5) 296 + 0x09, 0x55, // Usage (Contact Max) 298 + 0x25, 0x0a, // Logical Maximum (10) 300 + 0x75, 0x08, // Report Size (8) 302 + 0x95, 0x01, // Report Count (1) 304 + 0xb1, 0x02, // Feature (Data,Var,Abs) 306 + 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308 + 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311 + 0x85, 0x06, // Report ID (6) 313 + 0x15, 0x00, // Logical Minimum (0) 315 + 0x26, 0xff, 0x00, // Logical Maximum (255) 317 + 0x75, 0x08, // Report Size (8) 320 + 0x96, 0x00, 0x01, // Report Count (256) 322 + 0xb1, 0x02, // Feature (Data,Var,Abs) 325 + 0xc0, // End Collection 327 +}; + +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); + + if (!data) + return 0; /* EPERM check */ + + __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); + + return sizeof(fixed_rdesc); +} + +/* + * This tablet reports the 3rd button through invert, but this conflict + * with the normal eraser mode. + * Fortunately, before entering eraser mode, (so Invert = 1), + * the tablet always sends an out-of-proximity event. + * So we can detect that single event and: + * - if there was none but the invert bit was toggled: this is the + * third button + * - if there was this out-of-proximity event, we are entering + * eraser mode, and we will until the next out-of-proximity. + */ +SEC("fmod_ret/hid_bpf_device_event") +int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); + + if (!data) + return 0; /* EPERM check */ + + if (data[0] != 0x0a) /* not the pen report ID */ + return 0; + + /* stylus is out of range */ + if (!(data[1] & 0x40)) { + prev_was_out_of_range = true; + in_eraser_mode = false; + return 0; + } + + /* going into eraser mode (Invert = 1) only happens after an + * out of range event + */ + if (prev_was_out_of_range && (data[1] & 0x18)) + in_eraser_mode = true; + + /* eraser mode works fine */ + if (in_eraser_mode) + return 0; + + /* copy the Invert bit reported for the 3rd button in bit 7 */ + if (data[1] & 0x08) + data[1] |= 0x20; + + /* clear Invert bit now that it was copied */ + data[1] &= 0xf7; + + prev_was_out_of_range = false; + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + ctx->retval = ctx->rdesc_size != 328; + if (ctx->retval) + ctx->retval = -EINVAL; + + /* ensure the kernel isn't fixed already */ + if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */ + ctx->retval = -EINVAL; + + struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid); + + if (!hctx) { + return ctx->retval = -EINVAL; + return 0; + } + + const char *name = hctx->hid->name; + + /* strip out TEST_PREFIX */ + if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1)) + name += sizeof(TEST_PREFIX) - 1; + + if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19))) + ctx->retval = -EINVAL; + + hid_bpf_release_context(hctx); + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 0cd1465cac52d7d5b4584a29f97bddc5e8bb421f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 10 Apr 2024 19:19:29 +0200 Subject: HID: bpf: add in-tree HID-BPF fix for the Raptor Mach 2 This device is already fixed by "HID: do not assume HAT Switch logical max < 8", but for people without the fix already, having the HID-BPF locally can fix the device while they wait for their distribution to update. Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-9-a8bf16033ef8@kernel.org Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c | 185 ++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c (limited to 'drivers/hid') diff --git a/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c new file mode 100644 index 000000000000..dc26a7677d36 --- /dev/null +++ b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024 Benjamin Tissoires + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_BETOP_2185PC 0x11C0 +#define PID_RAPTOR_MACH_2 0x5606 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_BETOP_2185PC, PID_RAPTOR_MACH_2), +); + +/* + * For reference, this is the fixed report descriptor + * + * static const __u8 fixed_rdesc[] = { + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x04, // Usage (Joystick) 2 + * 0xa1, 0x01, // Collection (Application) 4 + * 0x05, 0x01, // Usage Page (Generic Desktop) 6 + * 0x85, 0x01, // Report ID (1) 8 + * 0x05, 0x01, // Usage Page (Generic Desktop) 10 + * 0x09, 0x30, // Usage (X) 12 + * 0x75, 0x10, // Report Size (16) 14 + * 0x95, 0x01, // Report Count (1) 16 + * 0x15, 0x00, // Logical Minimum (0) 18 + * 0x26, 0xff, 0x07, // Logical Maximum (2047) 20 + * 0x46, 0xff, 0x07, // Physical Maximum (2047) 23 + * 0x81, 0x02, // Input (Data,Var,Abs) 26 + * 0x05, 0x01, // Usage Page (Generic Desktop) 28 + * 0x09, 0x31, // Usage (Y) 30 + * 0x75, 0x10, // Report Size (16) 32 + * 0x95, 0x01, // Report Count (1) 34 + * 0x15, 0x00, // Logical Minimum (0) 36 + * 0x26, 0xff, 0x07, // Logical Maximum (2047) 38 + * 0x46, 0xff, 0x07, // Physical Maximum (2047) 41 + * 0x81, 0x02, // Input (Data,Var,Abs) 44 + * 0x05, 0x01, // Usage Page (Generic Desktop) 46 + * 0x09, 0x33, // Usage (Rx) 48 + * 0x75, 0x10, // Report Size (16) 50 + * 0x95, 0x01, // Report Count (1) 52 + * 0x15, 0x00, // Logical Minimum (0) 54 + * 0x26, 0xff, 0x03, // Logical Maximum (1023) 56 + * 0x46, 0xff, 0x03, // Physical Maximum (1023) 59 + * 0x81, 0x02, // Input (Data,Var,Abs) 62 + * 0x05, 0x00, // Usage Page (Undefined) 64 + * 0x09, 0x00, // Usage (Undefined) 66 + * 0x75, 0x10, // Report Size (16) 68 + * 0x95, 0x01, // Report Count (1) 70 + * 0x15, 0x00, // Logical Minimum (0) 72 + * 0x26, 0xff, 0x03, // Logical Maximum (1023) 74 + * 0x46, 0xff, 0x03, // Physical Maximum (1023) 77 + * 0x81, 0x02, // Input (Data,Var,Abs) 80 + * 0x05, 0x01, // Usage Page (Generic Desktop) 82 + * 0x09, 0x32, // Usage (Z) 84 + * 0x75, 0x10, // Report Size (16) 86 + * 0x95, 0x01, // Report Count (1) 88 + * 0x15, 0x00, // Logical Minimum (0) 90 + * 0x26, 0xff, 0x03, // Logical Maximum (1023) 92 + * 0x46, 0xff, 0x03, // Physical Maximum (1023) 95 + * 0x81, 0x02, // Input (Data,Var,Abs) 98 + * 0x05, 0x01, // Usage Page (Generic Desktop) 100 + * 0x09, 0x35, // Usage (Rz) 102 + * 0x75, 0x10, // Report Size (16) 104 + * 0x95, 0x01, // Report Count (1) 106 + * 0x15, 0x00, // Logical Minimum (0) 108 + * 0x26, 0xff, 0x03, // Logical Maximum (1023) 110 + * 0x46, 0xff, 0x03, // Physical Maximum (1023) 113 + * 0x81, 0x02, // Input (Data,Var,Abs) 116 + * 0x05, 0x01, // Usage Page (Generic Desktop) 118 + * 0x09, 0x34, // Usage (Ry) 120 + * 0x75, 0x10, // Report Size (16) 122 + * 0x95, 0x01, // Report Count (1) 124 + * 0x15, 0x00, // Logical Minimum (0) 126 + * 0x26, 0xff, 0x07, // Logical Maximum (2047) 128 + * 0x46, 0xff, 0x07, // Physical Maximum (2047) 131 + * 0x81, 0x02, // Input (Data,Var,Abs) 134 + * 0x05, 0x01, // Usage Page (Generic Desktop) 136 + * 0x09, 0x36, // Usage (Slider) 138 + * 0x75, 0x10, // Report Size (16) 140 + * 0x95, 0x01, // Report Count (1) 142 + * 0x15, 0x00, // Logical Minimum (0) 144 + * 0x26, 0xff, 0x03, // Logical Maximum (1023) 146 + * 0x46, 0xff, 0x03, // Physical Maximum (1023) 149 + * 0x81, 0x02, // Input (Data,Var,Abs) 152 + * 0x05, 0x09, // Usage Page (Button) 154 + * 0x19, 0x01, // Usage Minimum (1) 156 + * 0x2a, 0x1d, 0x00, // Usage Maximum (29) 158 + * 0x15, 0x00, // Logical Minimum (0) 161 + * 0x25, 0x01, // Logical Maximum (1) 163 + * 0x75, 0x01, // Report Size (1) 165 + * 0x96, 0x80, 0x00, // Report Count (128) 167 + * 0x81, 0x02, // Input (Data,Var,Abs) 170 + * 0x05, 0x01, // Usage Page (Generic Desktop) 172 + * 0x09, 0x39, // Usage (Hat switch) 174 + * 0x26, 0x07, 0x00, // Logical Maximum (7) 176 // changed (was 239) + * 0x46, 0x68, 0x01, // Physical Maximum (360) 179 + * 0x65, 0x14, // Unit (EnglishRotation: deg) 182 + * 0x75, 0x10, // Report Size (16) 184 + * 0x95, 0x01, // Report Count (1) 186 + * 0x81, 0x42, // Input (Data,Var,Abs,Null) 188 + * 0x05, 0x01, // Usage Page (Generic Desktop) 190 + * 0x09, 0x00, // Usage (Undefined) 192 + * 0x75, 0x08, // Report Size (8) 194 + * 0x95, 0x1d, // Report Count (29) 196 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 198 + * 0x15, 0x00, // Logical Minimum (0) 200 + * 0x26, 0xef, 0x00, // Logical Maximum (239) 202 + * 0x85, 0x58, // Report ID (88) 205 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 207 + * 0x46, 0xff, 0x00, // Physical Maximum (255) 210 + * 0x75, 0x08, // Report Size (8) 213 + * 0x95, 0x3f, // Report Count (63) 215 + * 0x09, 0x00, // Usage (Undefined) 217 + * 0x91, 0x02, // Output (Data,Var,Abs) 219 + * 0x85, 0x59, // Report ID (89) 221 + * 0x75, 0x08, // Report Size (8) 223 + * 0x95, 0x80, // Report Count (128) 225 + * 0x09, 0x00, // Usage (Undefined) 227 + * 0xb1, 0x02, // Feature (Data,Var,Abs) 229 + * 0xc0, // End Collection 231 + * }; + */ + +/* + * We need to amend the report descriptor for the following: + * - the joystick sends its hat_switch data between 0 and 239 but + * the kernel expects the logical max to stick into a signed 8 bits + * integer. We thus divide it by 30 to match what other joysticks are + * doing + */ +SEC("fmod_ret/hid_bpf_rdesc_fixup") +int BPF_PROG(hid_fix_rdesc_raptor_mach_2, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); + + if (!data) + return 0; /* EPERM check */ + + data[177] = 0x07; + + return 0; +} + +/* + * The hat_switch value at offsets 33 and 34 (16 bits) needs + * to be reduced to a single 8 bit signed integer. So we + * divide it by 30. + * Byte 34 is always null, so it is ignored. + */ +SEC("fmod_ret/hid_bpf_device_event") +int BPF_PROG(raptor_mach_2_fix_hat_switch, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 64 /* size */); + + if (!data) + return 0; /* EPERM check */ + + if (data[0] != 0x01) /* not the joystick report ID */ + return 0; + + data[33] /= 30; + + return 0; +} + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + ctx->retval = ctx->rdesc_size != 232; + if (ctx->retval) + ctx->retval = -EINVAL; + + /* ensure the kernel isn't fixed already */ + if (ctx->rdesc[177] != 0xef) /* Logical Max of 239 */ + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3