Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'hid-for-linus-2025032601' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

- PlayStation 5 controllers support (Alex Henrie)

- big revamp and modernization of the aged hid-pidff force feedback
driver (Tomasz Pakuła)

- conversion of hid-lg-g15 to standard multicolor LED API (Kate Hsuan)

- improvement of behavior of Human Presence Sensor (HPD) in amd_sfh
driver (Mario Limonciello)

- other assorted fixes, code cleanups and device ID additions

* tag 'hid-for-linus-2025032601' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (70 commits)
HID: remove superfluous (and wrong) Makefile entry for CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER
HID: Intel-thc-hid: Intel-quickspi: Correct device state names gramatically
HID: wacom: Remove static WACOM_PKGLEN_MAX limit
HID: amd_sfh: Don't show wrong status for amd_sfh_hpd_info()
HID: amd_sfh: Default to HPD disabled
HID: amd_sfh: Allow configuring whether HPD is enabled or disabled
HID: pidff: Fix set_device_control()
HID: pidff: Fix 90 degrees direction name North -> East
HID: pidff: Compute INFINITE value instead of using hardcoded 0xffff
HID: pidff: Clamp effect playback LOOP_COUNT value
HID: pidff: Rename two functions to align them with naming convention
HID: lenovo: silence unreachable code warning
HID: lenovo: Fix to ensure the data as __le32 instead of u32
HID: bpf: add a v6.11+ compatible BPF fixup for the XPPen ACK05 remote
HID: bpf: new hid_bpf_async.h common header
HID: bpf: import new kfunc from v6.10 & v6.11
HID: bpf: add support for the XP-Pen Artist Pro 19 (gen2)
HID: bpf: Added updated Kamvas Pro 19 descriptor
HID: bpf: Suppress bogus F13 trigger on Sirius keyboard full fan shortcut
HID: bpf: Add support for the default firmware mode of the Huion K20
...

+3057 -440
+13
Documentation/ABI/testing/sysfs-driver-amd-sfh
··· 1 + What: /sys/bus/pci/drivers/pcie_mp2_amd/*/hpd 2 + Date: April 2025 3 + Contact: mario.limonciello@amd.com 4 + Description: 5 + Human presence detection (HPD) enable/disable. 6 + When HPD is enabled, the device will be able to detect the 7 + presence of a human and will send an interrupt that can be 8 + used to wake the system from a low power state. 9 + When HPD is disabled, the device will not be able to detect 10 + the presence of a human. 11 + 12 + Access: Read/Write 13 + Valid values: enabled/disabled
+13
Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
··· 1 + What: /sys/bus/hid/drivers/hid-appletb-kbd/<dev>/mode 2 + Date: September, 2023 3 + KernelVersion: 6.5 4 + Contact: linux-input@vger.kernel.org 5 + Description: 6 + The set of keys displayed on the Touch Bar. 7 + Valid values are: 8 + == ================= 9 + 0 Escape key only 10 + 1 Function keys 11 + 2 Media/brightness keys 12 + 3 None 13 + == =================
+8
MAINTAINERS
··· 10364 10364 F: drivers/iio/*/hid-* 10365 10365 F: include/linux/hid-sensor-* 10366 10366 10367 + HID UNIVERSAL PIDFF DRIVER 10368 + M: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com> 10369 + M: Oleg Makarenko <oleg@makarenk.ooo> 10370 + L: linux-input@vger.kernel.org 10371 + S: Maintained 10372 + B: https://github.com/JacKeTUs/universal-pidff/issues 10373 + F: drivers/hid/hid-universal-pidff.c 10374 + 10367 10375 HID VRC-2 CAR CONTROLLER DRIVER 10368 10376 M: Marcus Folkesson <marcus.folkesson@gmail.com> 10369 10377 L: linux-input@vger.kernel.org
+40
drivers/hid/Kconfig
··· 148 148 149 149 Say Y here if you want support for Apple infrared remote control. 150 150 151 + config HID_APPLETB_BL 152 + tristate "Apple Touch Bar Backlight" 153 + depends on BACKLIGHT_CLASS_DEVICE 154 + help 155 + Say Y here if you want support for the backlight of Touch Bars on x86 156 + MacBook Pros. 157 + 158 + To compile this driver as a module, choose M here: the 159 + module will be called hid-appletb-bl. 160 + 161 + config HID_APPLETB_KBD 162 + tristate "Apple Touch Bar Keyboard Mode" 163 + depends on USB_HID 164 + depends on BACKLIGHT_CLASS_DEVICE 165 + depends on INPUT 166 + select INPUT_SPARSEKMAP 167 + select HID_APPLETB_BL 168 + help 169 + Say Y here if you want support for the keyboard mode (escape, 170 + function, media and brightness keys) of Touch Bars on x86 MacBook 171 + Pros. 172 + 173 + To compile this driver as a module, choose M here: the 174 + module will be called hid-appletb-kbd. 175 + 151 176 config HID_ASUS 152 177 tristate "Asus" 153 178 depends on USB_HID ··· 628 603 tristate "Logitech devices" 629 604 depends on USB_HID 630 605 depends on LEDS_CLASS 606 + depends on LEDS_CLASS_MULTICOLOR 631 607 default !EXPERT 632 608 help 633 609 Support for Logitech devices that are not fully compliant with HID standard. ··· 1245 1219 U2F Zero only supports blinking its LED, so this driver doesn't 1246 1220 allow setting the brightness to anything but 1, which will 1247 1221 trigger a single blink and immediately reset back to 0. 1222 + 1223 + config HID_UNIVERSAL_PIDFF 1224 + tristate "universal-pidff: extended USB PID driver compatibility and usage" 1225 + depends on USB_HID 1226 + depends on HID_PID 1227 + help 1228 + Extended PID support for selected devices. 1229 + 1230 + Contains report fixups, extended usable button range and 1231 + pidff quirk management to extend compatibility with slightly 1232 + non-compliant USB PID devices and better fuzz/flat values for 1233 + high precision direct drive devices. 1234 + 1235 + Supports Moza Racing, Cammus, VRS, FFBeast and more. 1248 1236 1249 1237 config HID_WACOM 1250 1238 tristate "Wacom Intuos/Graphire tablet support (USB)"
+3 -1
drivers/hid/Makefile
··· 29 29 obj-$(CONFIG_HID_ACRUX) += hid-axff.o 30 30 obj-$(CONFIG_HID_APPLE) += hid-apple.o 31 31 obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o 32 + obj-$(CONFIG_HID_APPLETB_BL) += hid-appletb-bl.o 33 + obj-$(CONFIG_HID_APPLETB_KBD) += hid-appletb-kbd.o 32 34 obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o 33 35 obj-$(CONFIG_HID_ASUS) += hid-asus.o 34 36 obj-$(CONFIG_HID_AUREAL) += hid-aureal.o ··· 142 140 hid-uclogic-params.o 143 141 obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o 144 142 obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o 143 + obj-$(CONFIG_HID_UNIVERSAL_PIDFF) += hid-universal-pidff.o 145 144 obj-$(CONFIG_HID_LED) += hid-led.o 146 145 obj-$(CONFIG_HID_XIAOMI) += hid-xiaomi.o 147 146 obj-$(CONFIG_HID_XINMO) += hid-xinmo.o ··· 169 166 obj-$(CONFIG_I2C_HID_CORE) += i2c-hid/ 170 167 171 168 obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ 172 - obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ 173 169 174 170 obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ 175 171
+1
drivers/hid/amd-sfh-hid/amd_sfh_common.h
··· 42 42 43 43 struct sfh_dev_status { 44 44 bool is_hpd_present; 45 + bool is_hpd_enabled; 45 46 bool is_als_present; 46 47 bool is_sra_present; 47 48 };
+58
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
··· 18 18 #include <linux/iopoll.h> 19 19 #include <linux/module.h> 20 20 #include <linux/slab.h> 21 + #include <linux/string_choices.h> 21 22 22 23 #include "amd_sfh_pcie.h" 23 24 #include "sfh1_1/amd_sfh_init.h" ··· 331 330 { } 332 331 }; 333 332 333 + static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf) 334 + { 335 + struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); 336 + 337 + return sysfs_emit(buf, "%s\n", str_enabled_disabled(mp2->dev_en.is_hpd_enabled)); 338 + } 339 + 340 + static ssize_t hpd_store(struct device *dev, 341 + struct device_attribute *attr, 342 + const char *buf, size_t count) 343 + { 344 + struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); 345 + bool enabled; 346 + int ret; 347 + 348 + ret = kstrtobool(buf, &enabled); 349 + if (ret) 350 + return ret; 351 + 352 + mp2->sfh1_1_ops->toggle_hpd(mp2, enabled); 353 + 354 + return count; 355 + } 356 + static DEVICE_ATTR_RW(hpd); 357 + 358 + static umode_t sfh_attr_is_visible(struct kobject *kobj, struct attribute *attr, int idx) 359 + { 360 + struct device *dev = kobj_to_dev(kobj); 361 + struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); 362 + 363 + if (!mp2->sfh1_1_ops || !mp2->dev_en.is_hpd_present) 364 + return 0; 365 + 366 + return attr->mode; 367 + } 368 + 369 + static struct attribute *sfh_attrs[] = { 370 + &dev_attr_hpd.attr, 371 + NULL, 372 + }; 373 + 374 + static struct attribute_group sfh_attr_group = { 375 + .attrs = sfh_attrs, 376 + .is_visible = sfh_attr_is_visible, 377 + }; 378 + 379 + static const struct attribute_group *amd_sfh_groups[] = { 380 + &sfh_attr_group, 381 + NULL, 382 + }; 383 + 334 384 static void sfh1_1_init_work(struct work_struct *work) 335 385 { 336 386 struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work); ··· 393 341 394 342 amd_sfh_clear_intr(mp2); 395 343 mp2->init_done = 1; 344 + 345 + rc = sysfs_update_group(&mp2->pdev->dev.kobj, &sfh_attr_group); 346 + if (rc) 347 + dev_warn(&mp2->pdev->dev, "failed to update sysfs group\n"); 348 + 396 349 } 397 350 398 351 static void sfh_init_work(struct work_struct *work) ··· 544 487 .driver.pm = &amd_mp2_pm_ops, 545 488 .shutdown = amd_sfh_shutdown, 546 489 .remove = amd_sfh_remove, 490 + .dev_groups = amd_sfh_groups, 547 491 }; 548 492 module_pci_driver(amd_mp2_pci_driver); 549 493
+48 -2
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
··· 212 212 switch (cl_data->sensor_idx[i]) { 213 213 case HPD_IDX: 214 214 privdata->dev_en.is_hpd_present = true; 215 + privdata->dev_en.is_hpd_enabled = true; 216 + amd_sfh_toggle_hpd(privdata, false); 215 217 break; 216 218 case ALS_IDX: 217 219 privdata->dev_en.is_als_present = true; ··· 257 255 } 258 256 259 257 for (i = 0; i < cl_data->num_hid_devices; i++) { 258 + /* leave HPD alone; policy is controlled by sysfs */ 259 + if (cl_data->sensor_idx[i] == HPD_IDX) 260 + continue; 261 + 260 262 if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { 261 263 info.sensor_idx = cl_data->sensor_idx[i]; 262 264 mp2->mp2_ops->start(mp2, info); ··· 291 285 } 292 286 293 287 for (i = 0; i < cl_data->num_hid_devices; i++) { 294 - if (cl_data->sensor_idx[i] != HPD_IDX && 295 - cl_data->sensor_sts[i] == SENSOR_ENABLED) { 288 + /* leave HPD alone; policy is controlled by sysfs */ 289 + if (cl_data->sensor_idx[i] == HPD_IDX) 290 + continue; 291 + if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { 296 292 mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 297 293 status = amd_sfh_wait_for_response 298 294 (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR); ··· 310 302 311 303 cancel_delayed_work_sync(&cl_data->work_buffer); 312 304 amd_sfh_clear_intr(mp2); 305 + } 306 + 307 + void amd_sfh_toggle_hpd(struct amd_mp2_dev *mp2, bool enabled) 308 + { 309 + struct amdtp_cl_data *cl_data = mp2->cl_data; 310 + struct amd_mp2_sensor_info info; 311 + int i, status; 312 + 313 + if (mp2->dev_en.is_hpd_enabled == enabled) 314 + return; 315 + 316 + for (i = 0; i < cl_data->num_hid_devices; i++) { 317 + if (cl_data->sensor_idx[i] != HPD_IDX) 318 + continue; 319 + info.sensor_idx = cl_data->sensor_idx[i]; 320 + if (enabled) { 321 + mp2->mp2_ops->start(mp2, info); 322 + status = amd_sfh_wait_for_response 323 + (mp2, cl_data->sensor_idx[i], ENABLE_SENSOR); 324 + if (status == 0) 325 + status = SENSOR_ENABLED; 326 + if (status == SENSOR_ENABLED) 327 + cl_data->sensor_sts[i] = SENSOR_ENABLED; 328 + } else { 329 + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 330 + status = amd_sfh_wait_for_response 331 + (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR); 332 + if (status == 0) 333 + status = SENSOR_DISABLED; 334 + if (status != SENSOR_ENABLED) 335 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 336 + } 337 + dev_dbg(&mp2->pdev->dev, "toggle sid 0x%x (%s) status 0x%x\n", 338 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 339 + cl_data->sensor_sts[i]); 340 + break; 341 + } 342 + mp2->dev_en.is_hpd_enabled = enabled; 313 343 } 314 344 315 345 static void amd_mp2_pci_remove(void *privdata)
+3
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h
··· 15 15 16 16 struct amd_sfh1_1_ops { 17 17 int (*init)(struct amd_mp2_dev *mp2); 18 + void (*toggle_hpd)(struct amd_mp2_dev *mp2, bool enable); 18 19 }; 19 20 20 21 int amd_sfh1_1_init(struct amd_mp2_dev *mp2); 22 + void amd_sfh_toggle_hpd(struct amd_mp2_dev *mp2, bool enabled); 21 23 22 24 static const struct amd_sfh1_1_ops __maybe_unused sfh1_1_ops = { 23 25 .init = amd_sfh1_1_init, 26 + .toggle_hpd = amd_sfh_toggle_hpd, 24 27 }; 25 28 26 29 #endif
+1 -1
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
··· 129 129 if (!user_present) 130 130 return -EINVAL; 131 131 132 - if (!emp2 || !emp2->dev_en.is_hpd_present) 132 + if (!emp2 || !emp2->dev_en.is_hpd_present || !emp2->dev_en.is_hpd_enabled) 133 133 return -ENODEV; 134 134 135 135 hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4));
+71 -4
drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
··· 41 41 0x15, 0x00, // Logical Minimum (0) 22 42 42 0x25, 0x01, // Logical Maximum (1) 24 43 43 0x75, 0x01, // Report Size (1) 26 44 - 0x95, 0x05, // Report Count (5) 28 /* changed (was 5) */ 44 + 0x95, 0x05, // Report Count (5) 28 /* changed (was 6) */ 45 45 0x81, 0x02, // Input (Data,Var,Abs) 30 46 46 0x05, 0x09, // Usage Page (Button) /* inserted */ 47 47 0x09, 0x4a, // Usage (0x4a) /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */ ··· 189 189 0x96, 0x00, 0x01, // Report Count (256) 322 190 190 0xb1, 0x02, // Feature (Data,Var,Abs) 325 191 191 0xc0, // End Collection 327 192 + /* New in Firmware Version: HUION_M220_240524 */ 193 + 0x05, 0x01, // Usage Page (Generic Desktop) 328 194 + 0x09, 0x01, // Usage (Pointer) 330 195 + 0xa1, 0x01, // Collection (Application) 332 196 + 0x09, 0x01, // Usage (Pointer) 334 197 + 0xa1, 0x00, // Collection (Physical) 336 198 + 0x05, 0x09, // Usage Page (Button) 338 199 + 0x19, 0x01, // UsageMinimum (1) 340 200 + 0x29, 0x03, // UsageMaximum (3) 342 201 + 0x15, 0x00, // Logical Minimum (0) 344 202 + 0x25, 0x01, // Logical Maximum (1) 346 203 + 0x85, 0x02, // Report ID (2) 348 204 + 0x95, 0x03, // Report Count (3) 350 205 + 0x75, 0x01, // Report Size (1) 352 206 + 0x81, 0x02, // Input (Data,Var,Abs) 354 207 + 0x95, 0x01, // Report Count (1) 356 208 + 0x75, 0x05, // Report Size (5) 358 209 + 0x81, 0x01, // Input (Cnst,Arr,Abs) 360 210 + 0x05, 0x01, // Usage Page (Generic Desktop) 362 211 + 0x09, 0x30, // Usage (X) 364 212 + 0x09, 0x31, // Usage (Y) 366 213 + 0x15, 0x81, // Logical Minimum (-127) 368 214 + 0x25, 0x7f, // Logical Maximum (127) 370 215 + 0x75, 0x08, // Report Size (8) 372 216 + 0x95, 0x02, // Report Count (2) 374 217 + 0x81, 0x06, // Input (Data,Var,Rel) 376 218 + 0x95, 0x04, // Report Count (4) 378 219 + 0x75, 0x08, // Report Size (8) 380 220 + 0x81, 0x01, // Input (Cnst,Arr,Abs) 382 221 + 0xc0, // End Collection 384 222 + 0xc0, // End Collection 385 223 + 0x05, 0x0d, // Usage Page (Digitizers) 386 224 + 0x09, 0x05, // Usage (Touch Pad) 388 225 + 0xa1, 0x01, // Collection (Application) 390 226 + 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 392 227 + 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 395 228 + 0x15, 0x00, // Logical Minimum (0) 397 229 + 0x26, 0xff, 0x00, // Logical Maximum (255) 399 230 + 0x75, 0x08, // Report Size (8) 402 231 + 0x95, 0x10, // Report Count (16) 404 232 + 0x85, 0x3f, // Report ID (63) 406 233 + 0x81, 0x22, // Input (Data,Var,Abs,NoPref) 408 234 + 0xc0, // End Collection 410 235 + 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 411 236 + 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 414 237 + 0xa1, 0x01, // Collection (Application) 416 238 + 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 418 239 + 0x09, 0x0c, // Usage (Vendor Usage 0x0c) 421 240 + 0x15, 0x00, // Logical Minimum (0) 423 241 + 0x26, 0xff, 0x00, // Logical Maximum (255) 425 242 + 0x85, 0x44, // Report ID (68) 428 243 + 0x75, 0x08, // Report Size (8) 430 244 + 0x96, 0x6b, 0x05, // Report Count (1387) 432 245 + 0x81, 0x00, // Input (Data,Arr,Abs) 435 246 + 0xc0, // End Collection 437 192 247 }; 248 + 249 + #define PRE_240524_RDESC_SIZE 328 250 + #define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */ 251 + #define FW_240524_RDESC_SIZE 438 252 + #define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc) 193 253 194 254 SEC(HID_BPF_RDESC_FIXUP) 195 255 int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx) ··· 259 199 if (!data) 260 200 return 0; /* EPERM check */ 261 201 262 - __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); 202 + if (hctx->size == FW_240524_RDESC_SIZE) { 203 + __builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE); 204 + return sizeof(fixed_rdesc); 205 + } 263 206 264 - return sizeof(fixed_rdesc); 207 + __builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE); 208 + 209 + return PRE_240524_RDESC_FIXED_SIZE; 265 210 } 266 211 267 212 /* ··· 328 263 SEC("syscall") 329 264 int probe(struct hid_bpf_probe_args *ctx) 330 265 { 331 - ctx->retval = ctx->rdesc_size != 328; 266 + 267 + ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) || 268 + (ctx->rdesc_size == FW_240524_RDESC_SIZE)); 332 269 if (ctx->retval) 333 270 ctx->retval = -EINVAL; 334 271
+531
drivers/hid/bpf/progs/Huion__KeydialK20.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2024 Red Hat, Inc 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include "hid_report_helpers.h" 9 + #include <bpf/bpf_tracing.h> 10 + 11 + #define VID_HUION 0x256C 12 + #define PID_KEYDIAL_K20 0x0069 13 + 14 + HID_BPF_CONFIG( 15 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_KEYDIAL_K20), 16 + ); 17 + 18 + /* Filled in by udev-hid-bpf */ 19 + char UDEV_PROP_HUION_FIRMWARE_ID[64]; 20 + 21 + /* The prefix of the firmware ID we expect for this device. The full firmware 22 + * string has a date suffix, e.g. HUION_T21h_230511 23 + */ 24 + char EXPECTED_FIRMWARE_ID[] = "HUION_T21h_"; 25 + 26 + /* How this BPF program works: the tablet has two modes, firmware mode and 27 + * tablet mode. In firmware mode (out of the box) the tablet sends button events 28 + * as keyboard shortcuts and the dial as wheel but it's not forwarded by the kernel. 29 + * In tablet mode it uses a vendor specific hid report to report everything instead. 30 + * Depending on the mode some hid reports are never sent and the corresponding 31 + * devices are mute. 32 + * 33 + * To switch the tablet use e.g. https://github.com/whot/huion-switcher 34 + * or one of the tools from the digimend project 35 + * 36 + * This BPF currently works for both modes only. The huion-switcher tool sets the 37 + * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware 38 + * pad and pen reports (by making them vendor collections that are ignored). 39 + * If that property is not set we fix all hidraw nodes so the tablet works in 40 + * either mode though the drawback is that the device will show up twice if 41 + * you bind it to all event nodes 42 + * 43 + * Default report descriptor for the first exposed hidraw node: 44 + * 45 + * # HUION Huion Keydial_K20 46 + * # Report descriptor length: 18 bytes 47 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0 48 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3 49 + * # 0xa1, 0x01, // Collection (Application) 5 50 + * # 0x85, 0x08, // Report ID (8) 7 51 + * # 0x75, 0x58, // Report Size (88) 9 52 + * # 0x95, 0x01, // Report Count (1) 11 53 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13 54 + * # 0x81, 0x02, // Input (Data,Var,Abs) 15 55 + * # 0xc0, // End Collection 17 56 + * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0 57 + * 58 + * This report descriptor appears to be identical for all Huion devices. 59 + * 60 + * Second hidraw node is the Pad. This one sends the button events until the tablet is 61 + * switched to raw mode, then it's mute. 62 + * 63 + * # HUION Huion Keydial_K20 64 + * # Report descriptor length: 135 bytes 65 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 66 + * # 0x09, 0x06, // Usage (Keyboard) 2 67 + * # 0xa1, 0x01, // Collection (Application) 4 68 + * # 0x85, 0x03, // Report ID (3) 6 69 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8 70 + * # 0x19, 0xe0, // UsageMinimum (224) 10 71 + * # 0x29, 0xe7, // UsageMaximum (231) 12 72 + * # 0x15, 0x00, // Logical Minimum (0) 14 73 + * # 0x25, 0x01, // Logical Maximum (1) 16 74 + * # 0x75, 0x01, // Report Size (1) 18 75 + * # 0x95, 0x08, // Report Count (8) 20 76 + * # 0x81, 0x02, // Input (Data,Var,Abs) 22 77 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24 78 + * # 0x19, 0x00, // UsageMinimum (0) 26 79 + * # 0x29, 0xff, // UsageMaximum (255) 28 80 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 30 81 + * # 0x75, 0x08, // Report Size (8) 33 82 + * # 0x95, 0x06, // Report Count (6) 35 83 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 37 84 + * # 0xc0, // End Collection 39 85 + * # 0x05, 0x0c, // Usage Page (Consumer) 40 86 + * # 0x09, 0x01, // Usage (Consumer Control) 42 87 + * # 0xa1, 0x01, // Collection (Application) 44 88 + * # 0x85, 0x04, // Report ID (4) 46 89 + * # 0x05, 0x0c, // Usage Page (Consumer) 48 90 + * # 0x19, 0x00, // UsageMinimum (0) 50 91 + * # 0x2a, 0x80, 0x03, // UsageMaximum (896) 52 92 + * # 0x15, 0x00, // Logical Minimum (0) 55 93 + * # 0x26, 0x80, 0x03, // Logical Maximum (896) 57 94 + * # 0x75, 0x10, // Report Size (16) 60 95 + * # 0x95, 0x01, // Report Count (1) 62 96 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 64 97 + * # 0xc0, // End Collection 66 98 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 67 99 + * # 0x09, 0x02, // Usage (Mouse) 69 100 + * # 0xa1, 0x01, // Collection (Application) 71 101 + * # 0x09, 0x01, // Usage (Pointer) 73 102 + * # 0x85, 0x05, // Report ID (5) 75 103 + * # 0xa1, 0x00, // Collection (Physical) 77 104 + * # 0x05, 0x09, // Usage Page (Button) 79 105 + * # 0x19, 0x01, // UsageMinimum (1) 81 106 + * # 0x29, 0x05, // UsageMaximum (5) 83 107 + * # 0x15, 0x00, // Logical Minimum (0) 85 108 + * # 0x25, 0x01, // Logical Maximum (1) 87 109 + * # 0x95, 0x05, // Report Count (5) 89 110 + * # 0x75, 0x01, // Report Size (1) 91 111 + * # 0x81, 0x02, // Input (Data,Var,Abs) 93 112 + * # 0x95, 0x01, // Report Count (1) 95 113 + * # 0x75, 0x03, // Report Size (3) 97 114 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 99 115 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 101 116 + * # 0x09, 0x30, // Usage (X) 103 117 + * # 0x09, 0x31, // Usage (Y) 105 118 + * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 107 119 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 110 120 + * # 0x75, 0x10, // Report Size (16) 113 121 + * # 0x95, 0x02, // Report Count (2) 115 122 + * # 0x81, 0x06, // Input (Data,Var,Rel) 117 123 + * # 0x95, 0x01, // Report Count (1) 119 124 + * # 0x75, 0x08, // Report Size (8) 121 125 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 123 126 + * # 0x09, 0x38, // Usage (Wheel) 125 127 + * # 0x15, 0x81, // Logical Minimum (-127) 127 128 + * # 0x25, 0x7f, // Logical Maximum (127) 129 129 + * # 0x81, 0x06, // Input (Data,Var,Rel) 131 130 + * # 0xc0, // End Collection 133 131 + * # 0xc0, // End Collection 134 132 + * R: 135 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 05 0c 19 00 2a 80 03 15 00 26 80 03 75 10 95 01 81 00 c0 05 01 09 02 a1 01 09 01 85 05 a1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 16 00 80 26 ff 7f 7510 95 02 81 06 95 01 75 08 05 01 09 38 15 81 25 7f 81 06 c0 c0 133 + * 134 + * Third hidraw node is a multi-axis controller which sends the dial events 135 + * and the button inside the dial. If the tablet is switched to raw mode it is mute. 136 + * 137 + * # HUION Huion Keydial_K20 138 + * # Report descriptor length: 108 bytes 139 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 140 + * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2 141 + * # 0xa1, 0x01, // Collection (Application) 4 142 + * # 0x85, 0x11, // Report ID (17) 6 143 + * # 0x05, 0x0d, // Usage Page (Digitizers) 8 144 + * # 0x09, 0x21, // Usage (Puck) 10 145 + * # 0xa1, 0x02, // Collection (Logical) 12 146 + * # 0x15, 0x00, // Logical Minimum (0) 14 147 + * # 0x25, 0x01, // Logical Maximum (1) 16 148 + * # 0x75, 0x01, // Report Size (1) 18 149 + * # 0x95, 0x01, // Report Count (1) 20 150 + * # 0xa1, 0x00, // Collection (Physical) 22 151 + * # 0x05, 0x09, // Usage Page (Button) 24 152 + * # 0x09, 0x01, // Usage (Button 1) 26 153 + * # 0x81, 0x02, // Input (Data,Var,Abs) 28 154 + * # 0x05, 0x0d, // Usage Page (Digitizers) 30 155 + * # 0x09, 0x33, // Usage (Touch) 32 156 + * # 0x81, 0x02, // Input (Data,Var,Abs) 34 157 + * # 0x95, 0x06, // Report Count (6) 36 158 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38 159 + * # 0xa1, 0x02, // Collection (Logical) 40 160 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 42 161 + * # 0x09, 0x37, // Usage (Dial) 44 162 + * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46 163 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49 164 + * # 0x75, 0x10, // Report Size (16) 52 165 + * # 0x95, 0x01, // Report Count (1) 54 166 + * # 0x81, 0x06, // Input (Data,Var,Rel) 56 167 + * # 0x35, 0x00, // Physical Minimum (0) 58 168 + * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60 169 + * # 0x15, 0x00, // Logical Minimum (0) 63 170 + * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65 171 + * # 0x09, 0x48, // Usage (Resolution Multiplier) 68 172 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 70 173 + * # 0x45, 0x00, // Physical Maximum (0) 72 174 + * # 0xc0, // End Collection 74 175 + * # 0x75, 0x08, // Report Size (8) 75 176 + * # 0x95, 0x01, // Report Count (1) 77 177 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 79 178 + * # 0x75, 0x08, // Report Size (8) 81 179 + * # 0x95, 0x01, // Report Count (1) 83 180 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 85 181 + * # 0x75, 0x08, // Report Size (8) 87 182 + * # 0x95, 0x01, // Report Count (1) 89 183 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 91 184 + * # 0x75, 0x08, // Report Size (8) 93 185 + * # 0x95, 0x01, // Report Count (1) 95 186 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 187 + * # 0x75, 0x08, // Report Size (8) 99 188 + * # 0x95, 0x01, // Report Count (1) 101 189 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 103 190 + * # 0xc0, // End Collection 105 191 + * # 0xc0, // End Collection 106 192 + * # 0xc0, // End Collection 107 193 + * R: 108 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 194 + * 195 + */ 196 + 197 + #define PAD_REPORT_DESCRIPTOR_LENGTH 135 198 + #define PUCK_REPORT_DESCRIPTOR_LENGTH 108 199 + #define VENDOR_REPORT_DESCRIPTOR_LENGTH 18 200 + #define PAD_KBD_REPORT_ID 3 201 + #define PAD_CC_REPORT_ID 3 // never sends events 202 + #define PAD_MOUSE_REPORT_ID 4 // never sends events 203 + #define PUCK_REPORT_ID 17 204 + #define VENDOR_REPORT_ID 8 205 + #define PAD_KBD_REPORT_LENGTH 8 206 + #define PAD_CC_REPORT_LENGTH 3 207 + #define PAD_MOUSE_REPORT_LENGTH 7 208 + #define PUCK_REPORT_LENGTH 9 209 + #define VENDOR_REPORT_LENGTH 12 210 + 211 + __u32 last_button_state; 212 + 213 + static const __u8 disabled_rdesc_puck[] = { 214 + FixedSizeVendorReport(PUCK_REPORT_LENGTH) 215 + }; 216 + 217 + static const __u8 disabled_rdesc_pad[] = { 218 + FixedSizeVendorReport(PAD_KBD_REPORT_LENGTH) 219 + FixedSizeVendorReport(PAD_CC_REPORT_LENGTH) 220 + FixedSizeVendorReport(PAD_MOUSE_REPORT_LENGTH) 221 + }; 222 + 223 + static const __u8 fixed_rdesc_vendor[] = { 224 + UsagePage_GenericDesktop 225 + Usage_GD_Keypad 226 + CollectionApplication( 227 + // Byte 0 228 + // We send our pad events on the vendor report id because why not 229 + ReportId(VENDOR_REPORT_ID) 230 + UsagePage_Digitizers 231 + Usage_Dig_TabletFunctionKeys 232 + CollectionPhysical( 233 + // Byte 1 is a button so we look like a tablet 234 + Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad 235 + ReportCount(1) 236 + ReportSize(1) 237 + Input(Var|Abs) 238 + ReportCount(7) // Padding 239 + Input(Const) 240 + // Bytes 2/3 - x/y just exist so we get to be a tablet pad 241 + UsagePage_GenericDesktop 242 + Usage_GD_X 243 + Usage_GD_Y 244 + LogicalMinimum_i8(0x0) 245 + LogicalMaximum_i8(0x1) 246 + ReportCount(2) 247 + ReportSize(8) 248 + Input(Var|Abs) 249 + // Bytes 4-7 are the button state for 19 buttons + pad out to u32 250 + // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9 251 + UsagePage_Button 252 + UsageMinimum_i8(1) 253 + UsageMaximum_i8(10) 254 + LogicalMinimum_i8(0x0) 255 + LogicalMaximum_i8(0x1) 256 + ReportCount(10) 257 + ReportSize(1) 258 + Input(Var|Abs) 259 + // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2 260 + UsageMinimum_i8(0x31) 261 + UsageMaximum_i8(0x3a) 262 + ReportCount(9) 263 + ReportSize(1) 264 + Input(Var|Abs) 265 + ReportCount(13) 266 + ReportSize(1) 267 + Input(Const) // padding 268 + // Byte 6 is the wheel 269 + UsagePage_GenericDesktop 270 + Usage_GD_Wheel 271 + LogicalMinimum_i8(-1) 272 + LogicalMaximum_i8(1) 273 + ReportCount(1) 274 + ReportSize(8) 275 + Input(Var|Rel) 276 + ) 277 + // Make sure we match our original report length 278 + FixedSizeVendorReport(VENDOR_REPORT_LENGTH) 279 + ) 280 + }; 281 + 282 + /* Identical to fixed_rdesc_pad but with different FixedSizeVendorReport */ 283 + static const __u8 fixed_rdesc_pad[] = { 284 + UsagePage_GenericDesktop 285 + Usage_GD_Keypad 286 + CollectionApplication( 287 + // Byte 0 288 + // We send our pad events on the vendor report id because why not 289 + ReportId(VENDOR_REPORT_ID) 290 + UsagePage_Digitizers 291 + Usage_Dig_TabletFunctionKeys 292 + CollectionPhysical( 293 + // Byte 1 is a button so we look like a tablet 294 + Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad 295 + ReportCount(1) 296 + ReportSize(1) 297 + Input(Var|Abs) 298 + ReportCount(7) // Padding 299 + Input(Const) 300 + // Bytes 2/3 - x/y just exist so we get to be a tablet pad 301 + UsagePage_GenericDesktop 302 + Usage_GD_X 303 + Usage_GD_Y 304 + LogicalMinimum_i8(0x0) 305 + LogicalMaximum_i8(0x1) 306 + ReportCount(2) 307 + ReportSize(8) 308 + Input(Var|Abs) 309 + // Bytes 4-7 are the button state for 19 buttons + pad out to u32 310 + // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9 311 + UsagePage_Button 312 + UsageMinimum_i8(1) 313 + UsageMaximum_i8(10) 314 + LogicalMinimum_i8(0x0) 315 + LogicalMaximum_i8(0x1) 316 + ReportCount(10) 317 + ReportSize(1) 318 + Input(Var|Abs) 319 + // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2 320 + UsageMinimum_i8(0x31) 321 + UsageMaximum_i8(0x3a) 322 + ReportCount(9) 323 + ReportSize(1) 324 + Input(Var|Abs) 325 + ReportCount(13) 326 + ReportSize(1) 327 + Input(Const) // padding 328 + // Byte 6 is the wheel 329 + UsagePage_GenericDesktop 330 + Usage_GD_Wheel 331 + LogicalMinimum_i8(-1) 332 + LogicalMaximum_i8(1) 333 + ReportCount(1) 334 + ReportSize(8) 335 + Input(Var|Rel) 336 + ) 337 + // Make sure we match our original report lengths 338 + FixedSizeVendorReport(PAD_KBD_REPORT_LENGTH) 339 + FixedSizeVendorReport(PAD_CC_REPORT_LENGTH) 340 + FixedSizeVendorReport(PAD_MOUSE_REPORT_LENGTH) 341 + ) 342 + }; 343 + 344 + SEC(HID_BPF_RDESC_FIXUP) 345 + int BPF_PROG(k20_fix_rdesc, struct hid_bpf_ctx *hctx) 346 + { 347 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 348 + __s32 rdesc_size = hctx->size; 349 + __u8 have_fw_id; 350 + 351 + if (!data) 352 + return 0; /* EPERM check */ 353 + 354 + /* If we have a firmware ID and it matches our expected prefix, we 355 + * disable the default pad/puck nodes. They won't send events 356 + * but cause duplicate devices. 357 + */ 358 + have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID, 359 + EXPECTED_FIRMWARE_ID, 360 + sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0; 361 + if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) { 362 + if (have_fw_id) { 363 + __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad)); 364 + return sizeof(disabled_rdesc_pad); 365 + } else { 366 + __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); 367 + return sizeof(fixed_rdesc_pad); 368 + 369 + } 370 + } 371 + if (rdesc_size == PUCK_REPORT_DESCRIPTOR_LENGTH) { 372 + if (have_fw_id) { 373 + __builtin_memcpy(data, disabled_rdesc_puck, sizeof(disabled_rdesc_puck)); 374 + return sizeof(disabled_rdesc_puck); 375 + } 376 + } 377 + /* Always fix the vendor mode so the tablet will work even if nothing sets 378 + * the udev property (e.g. huion-switcher run manually) 379 + */ 380 + if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) { 381 + __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); 382 + return sizeof(fixed_rdesc_vendor); 383 + 384 + } 385 + return 0; 386 + } 387 + 388 + SEC(HID_BPF_DEVICE_EVENT) 389 + int BPF_PROG(k20_fix_events, struct hid_bpf_ctx *hctx) 390 + { 391 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); 392 + 393 + if (!data) 394 + return 0; /* EPERM check */ 395 + 396 + /* Only sent if tablet is in raw mode */ 397 + if (data[0] == VENDOR_REPORT_ID) { 398 + /* See fixed_rdesc_pad */ 399 + struct pad_report { 400 + __u8 report_id; 401 + __u8 btn_stylus:1; 402 + __u8 pad:7; 403 + __u8 x; 404 + __u8 y; 405 + __u32 buttons; 406 + __u8 wheel; 407 + } __attribute__((packed)) *pad_report; 408 + 409 + __u8 wheel = 0; 410 + 411 + /* Wheel report */ 412 + if (data[1] == 0xf1) { 413 + if (data[5] == 2) 414 + wheel = 0xff; 415 + else 416 + wheel = data[5]; 417 + } else { 418 + /* data[4..6] are the buttons, mapped correctly */ 419 + last_button_state = data[4] | (data[5] << 8) | (data[6] << 16); 420 + wheel = 0; // wheel 421 + } 422 + 423 + pad_report = (struct pad_report *)data; 424 + pad_report->report_id = VENDOR_REPORT_ID; 425 + pad_report->btn_stylus = 0; 426 + pad_report->x = 0; 427 + pad_report->y = 0; 428 + pad_report->buttons = last_button_state; 429 + pad_report->wheel = wheel; 430 + 431 + return sizeof(struct pad_report); 432 + } 433 + 434 + if (data[0] == PAD_KBD_REPORT_ID) { 435 + const __u8 button_mapping[] = { 436 + 0x0e, /* Button 1: K */ 437 + 0x0a, /* Button 2: G */ 438 + 0x0f, /* Button 3: L */ 439 + 0x4c, /* Button 4: Delete */ 440 + 0x0c, /* Button 5: I */ 441 + 0x07, /* Button 6: D */ 442 + 0x05, /* Button 7: B */ 443 + 0x08, /* Button 8: E */ 444 + 0x16, /* Button 9: S */ 445 + 0x1d, /* Button 10: Z */ 446 + 0x06, /* Button 11: C */ 447 + 0x19, /* Button 12: V */ 448 + 0xff, /* Button 13: LeftControl */ 449 + 0xff, /* Button 14: LeftAlt */ 450 + 0xff, /* Button 15: LeftShift */ 451 + 0x28, /* Button 16: Return Enter */ 452 + 0x2c, /* Button 17: Spacebar */ 453 + 0x11, /* Button 18: N */ 454 + }; 455 + /* See fixed_rdesc_pad */ 456 + struct pad_report { 457 + __u8 report_id; 458 + __u8 btn_stylus:1; 459 + __u8 pad:7; 460 + __u8 x; 461 + __u8 y; 462 + __u32 buttons; 463 + __u8 wheel; 464 + } __attribute__((packed)) *pad_report; 465 + int i, b; 466 + __u8 modifiers = data[1]; 467 + __u32 buttons = 0; 468 + 469 + if (modifiers & 0x01) { /* Control */ 470 + buttons |= BIT(12); 471 + } 472 + if (modifiers & 0x02) { /* Shift */ 473 + buttons |= BIT(14); 474 + } 475 + if (modifiers & 0x04) { /* Alt */ 476 + buttons |= BIT(13); 477 + } 478 + 479 + for (i = 2; i < PAD_KBD_REPORT_LENGTH; i++) { 480 + if (!data[i]) 481 + break; 482 + 483 + for (b = 0; b < ARRAY_SIZE(button_mapping); b++) { 484 + if (data[i] == button_mapping[b]) { 485 + buttons |= BIT(b); 486 + break; 487 + } 488 + } 489 + data[i] = 0; 490 + } 491 + 492 + pad_report = (struct pad_report *)data; 493 + pad_report->report_id = VENDOR_REPORT_ID; 494 + pad_report->btn_stylus = 0; 495 + pad_report->x = 0; 496 + pad_report->y = 0; 497 + pad_report->buttons = buttons; 498 + // The wheel happens on a different hidraw node but its 499 + // values are unreliable (as is the button inside the wheel). 500 + // So the wheel is simply always zero, if you want the wheel 501 + // to work reliably, use the tablet mode. 502 + pad_report->wheel = 0; 503 + 504 + return sizeof(struct pad_report); 505 + } 506 + 507 + return 0; 508 + } 509 + 510 + HID_BPF_OPS(keydial_k20) = { 511 + .hid_device_event = (void *)k20_fix_events, 512 + .hid_rdesc_fixup = (void *)k20_fix_rdesc, 513 + }; 514 + 515 + SEC("syscall") 516 + int probe(struct hid_bpf_probe_args *ctx) 517 + { 518 + switch (ctx->rdesc_size) { 519 + case PAD_REPORT_DESCRIPTOR_LENGTH: 520 + case PUCK_REPORT_DESCRIPTOR_LENGTH: 521 + case VENDOR_REPORT_DESCRIPTOR_LENGTH: 522 + ctx->retval = 0; 523 + break; 524 + default: 525 + ctx->retval = -EINVAL; 526 + } 527 + 528 + return 0; 529 + } 530 + 531 + char _license[] SEC("license") = "GPL";
+47
drivers/hid/bpf/progs/TUXEDO__Sirius-16-Gen1-and-Gen2.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* Copyright (c) 2025 TUXEDO Computers GmbH 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include <bpf/bpf_tracing.h> 9 + 10 + HID_BPF_CONFIG( 11 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 0x048D, 0x8910) 12 + ); 13 + 14 + SEC(HID_BPF_DEVICE_EVENT) 15 + int BPF_PROG(ignore_key_fix_event, struct hid_bpf_ctx *hid_ctx) 16 + { 17 + const int expected_length = 37; 18 + const int expected_report_id = 1; 19 + __u8 *data; 20 + int i; 21 + 22 + if (hid_ctx->size < expected_length) 23 + return 0; 24 + 25 + data = hid_bpf_get_data(hid_ctx, 0, expected_length); 26 + if (!data || data[0] != expected_report_id) 27 + return 0; 28 + 29 + // Zero out F13 (HID usage ID: 0x68) key press. 30 + // The first 6 parallel key presses (excluding modifier keys) are 31 + // encoded in an array containing usage IDs. 32 + for (i = 3; i < 9; ++i) 33 + if (data[i] == 0x68) 34 + data[i] = 0x00; 35 + // Additional parallel key presses starting with the 7th (excluding 36 + // modifier keys) are encoded as a bit flag with the offset being 37 + // the usage ID. 38 + data[22] &= 0xfe; 39 + 40 + return 0; 41 + } 42 + 43 + HID_BPF_OPS(ignore_button) = { 44 + .hid_device_event = (void *)ignore_key_fix_event, 45 + }; 46 + 47 + char _license[] SEC("license") = "GPL";
+330
drivers/hid/bpf/progs/XPPen__ACK05.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2024 Red Hat, Inc 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include "hid_report_helpers.h" 9 + #include <bpf/bpf_tracing.h> 10 + 11 + #define HID_BPF_ASYNC_MAX_CTX 1 12 + #include "hid_bpf_async.h" 13 + 14 + #define VID_UGEE 0x28BD 15 + /* same PID whether connected directly or through the provided dongle: */ 16 + #define PID_ACK05_REMOTE 0x0202 17 + 18 + 19 + HID_BPF_CONFIG( 20 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ACK05_REMOTE), 21 + ); 22 + 23 + /* 24 + * By default, the pad reports the buttons through a set of key sequences. 25 + * 26 + * The pad reports a classic keyboard report descriptor: 27 + * # HANVON UGEE Shortcut Remote 28 + * Report descriptor length: 102 bytes 29 + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 30 + * 0x09, 0x02, // Usage (Mouse) 2 31 + * 0xa1, 0x01, // Collection (Application) 4 32 + * 0x85, 0x09, // Report ID (9) 6 33 + * 0x09, 0x01, // Usage (Pointer) 8 34 + * 0xa1, 0x00, // Collection (Physical) 10 35 + * 0x05, 0x09, // Usage Page (Button) 12 36 + * 0x19, 0x01, // UsageMinimum (1) 14 37 + * 0x29, 0x03, // UsageMaximum (3) 16 38 + * 0x15, 0x00, // Logical Minimum (0) 18 39 + * 0x25, 0x01, // Logical Maximum (1) 20 40 + * 0x95, 0x03, // Report Count (3) 22 41 + * 0x75, 0x01, // Report Size (1) 24 42 + * 0x81, 0x02, // Input (Data,Var,Abs) 26 43 + * 0x95, 0x05, // Report Count (5) 28 44 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 30 45 + * 0x05, 0x01, // Usage Page (Generic Desktop) 32 46 + * 0x09, 0x30, // Usage (X) 34 47 + * 0x09, 0x31, // Usage (Y) 36 48 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 38 49 + * 0x95, 0x02, // Report Count (2) 41 50 + * 0x75, 0x10, // Report Size (16) 43 51 + * 0x81, 0x02, // Input (Data,Var,Abs) 45 52 + * 0x05, 0x0d, // Usage Page (Digitizers) 47 53 + * 0x09, 0x30, // Usage (Tip Pressure) 49 54 + * 0x26, 0xff, 0x07, // Logical Maximum (2047) 51 55 + * 0x95, 0x01, // Report Count (1) 54 56 + * 0x75, 0x10, // Report Size (16) 56 57 + * 0x81, 0x02, // Input (Data,Var,Abs) 58 58 + * 0xc0, // End Collection 60 59 + * 0xc0, // End Collection 61 60 + * 0x05, 0x01, // Usage Page (Generic Desktop) 62 61 + * 0x09, 0x06, // Usage (Keyboard) 64 62 + * 0xa1, 0x01, // Collection (Application) 66 63 + * 0x85, 0x06, // Report ID (6) 68 64 + * 0x05, 0x07, // Usage Page (Keyboard/Keypad) 70 65 + * 0x19, 0xe0, // UsageMinimum (224) 72 66 + * 0x29, 0xe7, // UsageMaximum (231) 74 67 + * 0x15, 0x00, // Logical Minimum (0) 76 68 + * 0x25, 0x01, // Logical Maximum (1) 78 69 + * 0x75, 0x01, // Report Size (1) 80 70 + * 0x95, 0x08, // Report Count (8) 82 71 + * 0x81, 0x02, // Input (Data,Var,Abs) 84 72 + * 0x05, 0x07, // Usage Page (Keyboard/Keypad) 86 73 + * 0x19, 0x00, // UsageMinimum (0) 88 74 + * 0x29, 0xff, // UsageMaximum (255) 90 75 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 92 76 + * 0x75, 0x08, // Report Size (8) 95 77 + * 0x95, 0x06, // Report Count (6) 97 78 + * 0x81, 0x00, // Input (Data,Arr,Abs) 99 79 + * 0xc0, // End Collection 101 80 + * 81 + * Each button gets assigned the following events: 82 + * 83 + * Buttons released: 06 00 00 00 00 00 00 00 84 + * Button 1: 06 01 12 00 00 00 00 00 -> LControl + o 85 + * Button 2: 06 01 11 00 00 00 00 00 -> LControl + n 86 + * Button 3: 06 00 3e 00 00 00 00 00 -> F5 87 + * Button 4: 06 02 00 00 00 00 00 00 -> LShift 88 + * Button 5: 06 01 00 00 00 00 00 00 -> LControl 89 + * Button 6: 06 04 00 00 00 00 00 00 -> LAlt 90 + * Button 7: 06 01 16 00 00 00 00 00 -> LControl + s 91 + * Button 8: 06 01 1d 00 00 00 00 00 -> LControl + z 92 + * Button 9: 06 00 2c 00 00 00 00 00 -> Space 93 + * Button 10: 06 03 1d 00 00 00 00 00 -> LControl + LShift + z 94 + * Wheel: 06 01 57 00 00 00 00 00 -> clockwise rotation (LControl + Keypad Plus) 95 + * Wheel: 06 01 56 00 00 00 00 00 -> counter-clockwise rotation 96 + * (LControl + Keypad Minus) 97 + * 98 + * However, multiple buttons can be pressed at the same time, and when this happens, 99 + * each button gets assigned a new slot in the Input (Data,Arr,Abs): 100 + * 101 + * Button 1 + 3: 06 01 12 3e 00 00 00 00 -> LControl + o + F5 102 + * 103 + * When a modifier is pressed (Button 4, 5, or 6), the assigned key is set to 00: 104 + * 105 + * Button 5 + 7: 06 01 00 16 00 00 00 00 -> LControl + s 106 + * 107 + * This is mostly fine, but with Button 8 and Button 10 sharing the same 108 + * key value ("z"), there are cases where we can not know which is which. 109 + * 110 + */ 111 + 112 + #define PAD_WIRED_DESCRIPTOR_LENGTH 102 113 + #define PAD_DONGLE_DESCRIPTOR_LENGTH 177 114 + #define STYLUS_DESCRIPTOR_LENGTH 109 115 + #define VENDOR_DESCRIPTOR_LENGTH 36 116 + #define PAD_REPORT_ID 6 117 + #define RAW_PAD_REPORT_ID 0xf0 118 + #define RAW_BATTERY_REPORT_ID 0xf2 119 + #define VENDOR_REPORT_ID 2 120 + #define PAD_REPORT_LENGTH 8 121 + #define VENDOR_REPORT_LENGTH 12 122 + 123 + __u16 last_button_state; 124 + 125 + static const __u8 disabled_rdesc[] = { 126 + // Make sure we match our original report length 127 + FixedSizeVendorReport(VENDOR_REPORT_LENGTH) 128 + }; 129 + 130 + static const __u8 fixed_rdesc_vendor[] = { 131 + UsagePage_GenericDesktop 132 + Usage_GD_Keypad 133 + CollectionApplication( 134 + // -- Byte 0 in report 135 + ReportId(RAW_PAD_REPORT_ID) 136 + // Byte 1 in report - same than report ID 137 + ReportCount(1) 138 + ReportSize(8) 139 + Input(Const) // padding (internal report ID) 140 + LogicalMaximum_i8(0) 141 + LogicalMaximum_i8(1) 142 + UsagePage_Digitizers 143 + Usage_Dig_TabletFunctionKeys 144 + CollectionPhysical( 145 + // Byte 2-3 is the button state 146 + UsagePage_Button 147 + UsageMinimum_i8(0x01) 148 + UsageMaximum_i8(0x0a) 149 + LogicalMinimum_i8(0x0) 150 + LogicalMaximum_i8(0x1) 151 + ReportCount(10) 152 + ReportSize(1) 153 + Input(Var|Abs) 154 + Usage_i8(0x31) // will be mapped as BTN_A / BTN_SOUTH 155 + ReportCount(1) 156 + Input(Var|Abs) 157 + ReportCount(5) // padding 158 + Input(Const) 159 + // Byte 4 in report - just exists so we get to be a tablet pad 160 + Usage_Dig_BarrelSwitch // BTN_STYLUS 161 + ReportCount(1) 162 + ReportSize(1) 163 + Input(Var|Abs) 164 + ReportCount(7) // padding 165 + Input(Const) 166 + // Bytes 5/6 in report - just exists so we get to be a tablet pad 167 + UsagePage_GenericDesktop 168 + Usage_GD_X 169 + Usage_GD_Y 170 + ReportCount(2) 171 + ReportSize(8) 172 + Input(Var|Abs) 173 + // Byte 7 in report is the dial 174 + Usage_GD_Wheel 175 + LogicalMinimum_i8(-1) 176 + LogicalMaximum_i8(1) 177 + ReportCount(1) 178 + ReportSize(8) 179 + Input(Var|Rel) 180 + ) 181 + // -- Byte 0 in report 182 + ReportId(RAW_BATTERY_REPORT_ID) 183 + // Byte 1 in report - same than report ID 184 + ReportCount(1) 185 + ReportSize(8) 186 + Input(Const) // padding (internal report ID) 187 + // Byte 2 in report - always 0x01 188 + Input(Const) // padding (internal report ID) 189 + UsagePage_Digitizers 190 + /* 191 + * We represent the device as a stylus to force the kernel to not 192 + * directly query its battery state. Instead the kernel will rely 193 + * only on the provided events. 194 + */ 195 + Usage_Dig_Stylus 196 + CollectionPhysical( 197 + // Byte 3 in report - battery value 198 + UsagePage_BatterySystem 199 + Usage_BS_AbsoluteStateOfCharge 200 + LogicalMinimum_i8(0) 201 + LogicalMaximum_i8(100) 202 + ReportCount(1) 203 + ReportSize(8) 204 + Input(Var|Abs) 205 + // Byte 4 in report - charging state 206 + Usage_BS_Charging 207 + LogicalMinimum_i8(0) 208 + LogicalMaximum_i8(1) 209 + ReportCount(1) 210 + ReportSize(8) 211 + Input(Var|Abs) 212 + ) 213 + ) 214 + }; 215 + 216 + SEC(HID_BPF_RDESC_FIXUP) 217 + int BPF_PROG(ack05_fix_rdesc, struct hid_bpf_ctx *hctx) 218 + { 219 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 220 + __s32 rdesc_size = hctx->size; 221 + 222 + if (!data) 223 + return 0; /* EPERM check */ 224 + 225 + if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) { 226 + /* 227 + * The vendor fixed rdesc is appended after the current one, 228 + * to keep the output reports working. 229 + */ 230 + __builtin_memcpy(data + rdesc_size, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); 231 + return sizeof(fixed_rdesc_vendor) + rdesc_size; 232 + } 233 + 234 + hid_set_name(hctx->hid, "Disabled by HID-BPF Hanvon Ugee Shortcut Remote"); 235 + 236 + __builtin_memcpy(data, disabled_rdesc, sizeof(disabled_rdesc)); 237 + return sizeof(disabled_rdesc); 238 + } 239 + 240 + static int HID_BPF_ASYNC_FUN(switch_to_raw_mode)(struct hid_bpf_ctx *hid) 241 + { 242 + static __u8 magic_0[32] = {0x02, 0xb0, 0x04, 0x00, 0x00}; 243 + int err; 244 + 245 + /* 246 + * The proprietary driver sends the 3 following packets after the 247 + * above one. 248 + * These don't seem to have any effect, so we don't send them to save 249 + * some processing time. 250 + * 251 + * static __u8 magic_1[32] = {0x02, 0xb4, 0x01, 0x00, 0x01}; 252 + * static __u8 magic_2[32] = {0x02, 0xb4, 0x01, 0x00, 0xff}; 253 + * static __u8 magic_3[32] = {0x02, 0xb8, 0x04, 0x00, 0x00}; 254 + */ 255 + 256 + err = hid_bpf_hw_output_report(hid, magic_0, sizeof(magic_0)); 257 + if (err < 0) 258 + return err; 259 + 260 + return 0; 261 + } 262 + 263 + SEC(HID_BPF_DEVICE_EVENT) 264 + int BPF_PROG(ack05_fix_events, struct hid_bpf_ctx *hctx) 265 + { 266 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH); 267 + int ret = 0; 268 + 269 + if (!data) 270 + return 0; /* EPERM check */ 271 + 272 + if (data[0] != VENDOR_REPORT_ID) 273 + return 0; 274 + 275 + /* reconnect event */ 276 + if (data[1] == 0xf8 && data[2] == 02 && data[3] == 0x01) 277 + HID_BPF_ASYNC_DELAYED_CALL(switch_to_raw_mode, hctx, 10); 278 + 279 + /* button event */ 280 + if (data[1] == RAW_PAD_REPORT_ID) { 281 + data[0] = data[1]; 282 + if (data[7] == 0x02) 283 + data[7] = 0xff; 284 + ret = 8; 285 + } else if (data[1] == RAW_BATTERY_REPORT_ID) { 286 + data[0] = data[1]; 287 + ret = 5; 288 + } 289 + 290 + return ret; 291 + } 292 + 293 + HID_BPF_OPS(xppen_ack05_remote) = { 294 + .hid_device_event = (void *)ack05_fix_events, 295 + .hid_rdesc_fixup = (void *)ack05_fix_rdesc, 296 + }; 297 + 298 + SEC("syscall") 299 + int probe(struct hid_bpf_probe_args *ctx) 300 + { 301 + switch (ctx->rdesc_size) { 302 + case PAD_WIRED_DESCRIPTOR_LENGTH: 303 + case PAD_DONGLE_DESCRIPTOR_LENGTH: 304 + case STYLUS_DESCRIPTOR_LENGTH: 305 + case VENDOR_DESCRIPTOR_LENGTH: 306 + ctx->retval = 0; 307 + break; 308 + default: 309 + ctx->retval = -EINVAL; 310 + break; 311 + } 312 + 313 + if (ctx->rdesc_size == VENDOR_DESCRIPTOR_LENGTH) { 314 + struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid); 315 + 316 + if (!hctx) { 317 + ctx->retval = -EINVAL; 318 + return 0; 319 + } 320 + 321 + ctx->retval = HID_BPF_ASYNC_INIT(switch_to_raw_mode) || 322 + switch_to_raw_mode(hctx); 323 + 324 + hid_bpf_release_context(hctx); 325 + } 326 + 327 + return 0; 328 + } 329 + 330 + char _license[] SEC("license") = "GPL";
+40 -4
drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c
··· 10 10 #define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */ 11 11 #define PID_ARTIST_PRO14_GEN2 0x095A 12 12 #define PID_ARTIST_PRO16_GEN2 0x095B 13 + #define PID_ARTIST_PRO19_GEN2 0x096A 13 14 14 15 HID_BPF_CONFIG( 15 16 HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO14_GEN2), 16 - HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO16_GEN2) 17 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO16_GEN2), 18 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO19_GEN2) 17 19 ); 18 20 19 21 /* ··· 24 22 * - when the eraser button is pressed and the stylus is touching the tablet, 25 23 * the device sends Tip Switch instead of sending Eraser 26 24 * 27 - * This descriptor uses physical dimensions of the 16" device. 25 + * This descriptor uses the physical dimensions of the 16" device. 28 26 */ 29 27 static const __u8 fixed_rdesc[] = { 30 28 0x05, 0x0d, // Usage Page (Digitizers) 0 ··· 102 100 data[62] = 0x62; 103 101 data[73] = 0x1c; 104 102 data[72] = 0xfd; 103 + } else if (hctx->hid->product == PID_ARTIST_PRO19_GEN2) { 104 + /* 19" screen reports 16.101" x 9.057" */ 105 + data[63] = 0x3e; 106 + data[62] = 0xe5; 107 + data[73] = 0x23; 108 + data[72] = 0x61; 105 109 } 106 110 107 111 return sizeof(fixed_rdesc); ··· 185 177 188, 186, 184, 182, 180, 178, 176, 174, 172 186 178 }; 187 179 180 + /* 19" inch screen 16.101" x 9.057" */ 181 + static const __u16 angle_offsets_horizontal_19[128] = { 182 + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 27, 29, 31, 33, 35, 37, 39, 41, 183 + 42, 44, 46, 48, 50, 51, 53, 55, 57, 58, 60, 62, 63, 65, 67, 68, 70, 71, 73, 74, 76, 184 + 77, 79, 80, 82, 83, 84, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 185 + 101, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 109, 110, 110, 111, 186 + 111, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 187 + 113, 113, 112, 112, 112, 112, 111, 111, 110, 110, 109, 109, 108, 108, 107, 106, 188 + 106, 105, 104, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 90 189 + }; 190 + static const __u16 angle_offsets_vertical_19[128] = { 191 + 0, 4, 7, 11, 14, 18, 21, 25, 28, 32, 35, 38, 42, 45, 49, 52, 56, 59, 62, 66, 69, 72, 192 + 75, 79, 82, 85, 88, 91, 95, 98, 101, 104, 107, 110, 113, 116, 118, 121, 124, 127, 193 + 129, 132, 135, 137, 140, 142, 145, 147, 150, 152, 154, 157, 159, 161, 163, 165, 167, 194 + 169, 171, 173, 174, 176, 178, 179, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 195 + 194, 195, 195, 196, 197, 198, 198, 199, 199, 200, 200, 201, 201, 201, 201, 201, 201, 196 + 201, 201, 201, 201, 201, 200, 200, 199, 199, 198, 198, 197, 196, 195, 195, 194, 193, 197 + 192, 190, 189, 188, 187, 185, 184, 183, 181, 179, 178, 176, 174, 173, 171, 169, 167, 198 + 165, 163, 161 199 + }; 200 + 188 201 static void compensate_coordinates_by_tilt(__u8 *data, const __u8 idx, 189 202 const __s8 tilt, const __u16 (*compensation_table)[128]) 190 203 { ··· 270 241 __s8 tilt_x = (__s8) data[8]; 271 242 __s8 tilt_y = (__s8) data[9]; 272 243 273 - if (hctx->hid->product == PID_ARTIST_PRO14_GEN2) { 244 + switch (hctx->hid->product) { 245 + case PID_ARTIST_PRO14_GEN2: 274 246 compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_14); 275 247 compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_14); 276 - } else if (hctx->hid->product == PID_ARTIST_PRO16_GEN2) { 248 + break; 249 + case PID_ARTIST_PRO16_GEN2: 277 250 compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_16); 278 251 compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_16); 252 + break; 253 + case PID_ARTIST_PRO19_GEN2: 254 + compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_19); 255 + compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_19); 256 + break; 279 257 } 280 258 281 259 return 0;
+219
drivers/hid/bpf/progs/hid_bpf_async.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only 2 + * Copyright (c) 2024 Benjamin Tissoires 3 + */ 4 + 5 + #ifndef __HID_BPF_ASYNC_H__ 6 + #define __HID_BPF_ASYNC_H__ 7 + 8 + #ifndef HID_BPF_ASYNC_MAX_CTX 9 + #error "HID_BPF_ASYNC_MAX_CTX should be set to the maximum number of concurrent async functions" 10 + #endif /* HID_BPF_ASYNC_MAX_CTX */ 11 + 12 + #define CLOCK_MONOTONIC 1 13 + 14 + typedef int (*hid_bpf_async_callback_t)(void *map, int *key, void *value); 15 + 16 + enum hid_bpf_async_state { 17 + HID_BPF_ASYNC_STATE_UNSET = 0, 18 + HID_BPF_ASYNC_STATE_INITIALIZING, 19 + HID_BPF_ASYNC_STATE_INITIALIZED, 20 + HID_BPF_ASYNC_STATE_STARTING, 21 + HID_BPF_ASYNC_STATE_RUNNING, 22 + }; 23 + 24 + struct hid_bpf_async_map_elem { 25 + struct bpf_spin_lock lock; 26 + enum hid_bpf_async_state state; 27 + struct bpf_timer t; 28 + struct bpf_wq wq; 29 + u32 hid; 30 + }; 31 + 32 + struct { 33 + __uint(type, BPF_MAP_TYPE_ARRAY); 34 + __uint(max_entries, HID_BPF_ASYNC_MAX_CTX); 35 + __type(key, u32); 36 + __type(value, struct hid_bpf_async_map_elem); 37 + } hid_bpf_async_ctx_map SEC(".maps"); 38 + 39 + /** 40 + * HID_BPF_ASYNC_CB: macro to define an async callback used in a bpf_wq 41 + * 42 + * The caller is responsible for allocating a key in the async map 43 + * with hid_bpf_async_get_ctx(). 44 + */ 45 + #define HID_BPF_ASYNC_CB(cb) \ 46 + cb(void *map, int *key, void *value); \ 47 + static __always_inline int \ 48 + ____##cb(struct hid_bpf_ctx *ctx); \ 49 + typeof(cb(0, 0, 0)) cb(void *map, int *key, void *value) \ 50 + { \ 51 + struct hid_bpf_async_map_elem *e; \ 52 + struct hid_bpf_ctx *ctx; \ 53 + \ 54 + e = (struct hid_bpf_async_map_elem *)value; \ 55 + ctx = hid_bpf_allocate_context(e->hid); \ 56 + if (!ctx) \ 57 + return 0; /* EPERM check */ \ 58 + \ 59 + e->state = HID_BPF_ASYNC_STATE_RUNNING; \ 60 + \ 61 + ____##cb(ctx); \ 62 + \ 63 + e->state = HID_BPF_ASYNC_STATE_INITIALIZED; \ 64 + hid_bpf_release_context(ctx); \ 65 + return 0; \ 66 + } \ 67 + static __always_inline int \ 68 + ____##cb 69 + 70 + /** 71 + * ASYNC: macro to automatically handle async callbacks contexts 72 + * 73 + * Needs to be used in conjunction with HID_BPF_ASYNC_INIT and HID_BPF_ASYNC_DELAYED_CALL 74 + */ 75 + #define HID_BPF_ASYNC_FUN(fun) \ 76 + fun(struct hid_bpf_ctx *ctx); \ 77 + int ____key__##fun; \ 78 + static int ____async_init_##fun(void) \ 79 + { \ 80 + ____key__##fun = hid_bpf_async_get_ctx(); \ 81 + if (____key__##fun < 0) \ 82 + return ____key__##fun; \ 83 + return 0; \ 84 + } \ 85 + static int HID_BPF_ASYNC_CB(____##fun##_cb)(struct hid_bpf_ctx *hctx) \ 86 + { \ 87 + return fun(hctx); \ 88 + } \ 89 + typeof(fun(0)) fun 90 + 91 + #define HID_BPF_ASYNC_INIT(fun) ____async_init_##fun() 92 + #define HID_BPF_ASYNC_DELAYED_CALL(fun, ctx, delay) \ 93 + hid_bpf_async_delayed_call(ctx, delay, ____key__##fun, ____##fun##_cb) 94 + 95 + /* 96 + * internal cb for starting the delayed work callback in a workqueue. 97 + */ 98 + static int __start_wq_timer_cb(void *map, int *key, void *value) 99 + { 100 + struct hid_bpf_async_map_elem *e = (struct hid_bpf_async_map_elem *)value; 101 + 102 + bpf_wq_start(&e->wq, 0); 103 + 104 + return 0; 105 + } 106 + 107 + static int hid_bpf_async_find_empty_key(void) 108 + { 109 + int i; 110 + 111 + bpf_for(i, 0, HID_BPF_ASYNC_MAX_CTX) { 112 + struct hid_bpf_async_map_elem *elem; 113 + int key = i; 114 + 115 + elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key); 116 + if (!elem) 117 + return -ENOMEM; /* should never happen */ 118 + 119 + bpf_spin_lock(&elem->lock); 120 + 121 + if (elem->state == HID_BPF_ASYNC_STATE_UNSET) { 122 + elem->state = HID_BPF_ASYNC_STATE_INITIALIZING; 123 + bpf_spin_unlock(&elem->lock); 124 + return i; 125 + } 126 + 127 + bpf_spin_unlock(&elem->lock); 128 + } 129 + 130 + return -EINVAL; 131 + } 132 + 133 + static int hid_bpf_async_get_ctx(void) 134 + { 135 + int key = hid_bpf_async_find_empty_key(); 136 + struct hid_bpf_async_map_elem *elem; 137 + int err; 138 + 139 + if (key < 0) 140 + return key; 141 + 142 + elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key); 143 + if (!elem) 144 + return -EINVAL; 145 + 146 + err = bpf_timer_init(&elem->t, &hid_bpf_async_ctx_map, CLOCK_MONOTONIC); 147 + if (err) 148 + return err; 149 + 150 + err = bpf_timer_set_callback(&elem->t, __start_wq_timer_cb); 151 + if (err) 152 + return err; 153 + 154 + err = bpf_wq_init(&elem->wq, &hid_bpf_async_ctx_map, 0); 155 + if (err) 156 + return err; 157 + 158 + elem->state = HID_BPF_ASYNC_STATE_INITIALIZED; 159 + 160 + return key; 161 + } 162 + 163 + static inline u64 ms_to_ns(u64 milliseconds) 164 + { 165 + return (u64)milliseconds * 1000UL * 1000UL; 166 + } 167 + 168 + static int hid_bpf_async_delayed_call(struct hid_bpf_ctx *hctx, u64 milliseconds, int key, 169 + hid_bpf_async_callback_t wq_cb) 170 + { 171 + struct hid_bpf_async_map_elem *elem; 172 + int err; 173 + 174 + elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key); 175 + if (!elem) 176 + return -EINVAL; 177 + 178 + bpf_spin_lock(&elem->lock); 179 + /* The wq must be: 180 + * - HID_BPF_ASYNC_STATE_INITIALIZED -> it's been initialized and ready to be called 181 + * - HID_BPF_ASYNC_STATE_RUNNING -> possible re-entry from the wq itself 182 + */ 183 + if (elem->state != HID_BPF_ASYNC_STATE_INITIALIZED && 184 + elem->state != HID_BPF_ASYNC_STATE_RUNNING) { 185 + bpf_spin_unlock(&elem->lock); 186 + return -EINVAL; 187 + } 188 + elem->state = HID_BPF_ASYNC_STATE_STARTING; 189 + bpf_spin_unlock(&elem->lock); 190 + 191 + elem->hid = hctx->hid->id; 192 + 193 + err = bpf_wq_set_callback(&elem->wq, wq_cb, 0); 194 + if (err) 195 + return err; 196 + 197 + if (milliseconds) { 198 + /* needed for every call because a cancel might unset this */ 199 + err = bpf_timer_set_callback(&elem->t, __start_wq_timer_cb); 200 + if (err) 201 + return err; 202 + 203 + err = bpf_timer_start(&elem->t, ms_to_ns(milliseconds), 0); 204 + if (err) 205 + return err; 206 + 207 + return 0; 208 + } 209 + 210 + return bpf_wq_start(&elem->wq, 0); 211 + } 212 + 213 + static inline int hid_bpf_async_call(struct hid_bpf_ctx *ctx, int key, 214 + hid_bpf_async_callback_t wq_cb) 215 + { 216 + return hid_bpf_async_delayed_call(ctx, 0, key, wq_cb); 217 + } 218 + 219 + #endif /* __HID_BPF_ASYNC_H__ */
+19
drivers/hid/bpf/progs/hid_bpf_helpers.h
··· 19 19 size_t buf__sz, 20 20 enum hid_report_type type, 21 21 enum hid_class_request reqtype) __ksym; 22 + extern int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, 23 + __u8 *buf, size_t buf__sz) __weak __ksym; 24 + extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx, 25 + enum hid_report_type type, 26 + __u8 *data, 27 + size_t buf__sz) __weak __ksym; 28 + extern int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, 29 + enum hid_report_type type, 30 + __u8 *data, 31 + size_t buf__sz) __weak __ksym; 32 + 33 + /* bpf_wq implementation */ 34 + extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym; 35 + extern int bpf_wq_start(struct bpf_wq *wq, unsigned int flags) __weak __ksym; 36 + extern int bpf_wq_set_callback_impl(struct bpf_wq *wq, 37 + int (callback_fn)(void *map, int *key, void *value), 38 + unsigned int flags__k, void *aux__ign) __ksym; 39 + #define bpf_wq_set_callback(wq, cb, flags) \ 40 + bpf_wq_set_callback_impl(wq, cb, flags, NULL) 22 41 23 42 #define HID_MAX_DESCRIPTOR_SIZE 4096 24 43 #define HID_IGNORE_EVENT -1
+204
drivers/hid/hid-appletb-bl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Apple Touch Bar Backlight Driver 4 + * 5 + * Copyright (c) 2017-2018 Ronald Tschalär 6 + * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com> 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/hid.h> 12 + #include <linux/backlight.h> 13 + #include <linux/device.h> 14 + 15 + #include "hid-ids.h" 16 + 17 + #define APPLETB_BL_ON 1 18 + #define APPLETB_BL_DIM 3 19 + #define APPLETB_BL_OFF 4 20 + 21 + #define HID_UP_APPLEVENDOR_TB_BL 0xff120000 22 + 23 + #define HID_VD_APPLE_TB_BRIGHTNESS 0xff120001 24 + #define HID_USAGE_AUX1 0xff120020 25 + #define HID_USAGE_BRIGHTNESS 0xff120021 26 + 27 + static int appletb_bl_def_brightness = 2; 28 + module_param_named(brightness, appletb_bl_def_brightness, int, 0444); 29 + MODULE_PARM_DESC(brightness, "Default brightness:\n" 30 + " 0 - Touchbar is off\n" 31 + " 1 - Dim brightness\n" 32 + " [2] - Full brightness"); 33 + 34 + struct appletb_bl { 35 + struct hid_field *aux1_field, *brightness_field; 36 + struct backlight_device *bdev; 37 + 38 + bool full_on; 39 + }; 40 + 41 + static const u8 appletb_bl_brightness_map[] = { 42 + APPLETB_BL_OFF, 43 + APPLETB_BL_DIM, 44 + APPLETB_BL_ON, 45 + }; 46 + 47 + static int appletb_bl_set_brightness(struct appletb_bl *bl, u8 brightness) 48 + { 49 + struct hid_report *report = bl->brightness_field->report; 50 + struct hid_device *hdev = report->device; 51 + int ret; 52 + 53 + ret = hid_set_field(bl->aux1_field, 0, 1); 54 + if (ret) { 55 + hid_err(hdev, "Failed to set auxiliary field (%pe)\n", ERR_PTR(ret)); 56 + return ret; 57 + } 58 + 59 + ret = hid_set_field(bl->brightness_field, 0, brightness); 60 + if (ret) { 61 + hid_err(hdev, "Failed to set brightness field (%pe)\n", ERR_PTR(ret)); 62 + return ret; 63 + } 64 + 65 + if (!bl->full_on) { 66 + ret = hid_hw_power(hdev, PM_HINT_FULLON); 67 + if (ret < 0) { 68 + hid_err(hdev, "Device didn't power on (%pe)\n", ERR_PTR(ret)); 69 + return ret; 70 + } 71 + 72 + bl->full_on = true; 73 + } 74 + 75 + hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 76 + 77 + if (brightness == APPLETB_BL_OFF) { 78 + hid_hw_power(hdev, PM_HINT_NORMAL); 79 + bl->full_on = false; 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + static int appletb_bl_update_status(struct backlight_device *bdev) 86 + { 87 + struct appletb_bl *bl = bl_get_data(bdev); 88 + u8 brightness; 89 + 90 + if (backlight_is_blank(bdev)) 91 + brightness = APPLETB_BL_OFF; 92 + else 93 + brightness = appletb_bl_brightness_map[backlight_get_brightness(bdev)]; 94 + 95 + return appletb_bl_set_brightness(bl, brightness); 96 + } 97 + 98 + static const struct backlight_ops appletb_bl_backlight_ops = { 99 + .options = BL_CORE_SUSPENDRESUME, 100 + .update_status = appletb_bl_update_status, 101 + }; 102 + 103 + static int appletb_bl_probe(struct hid_device *hdev, const struct hid_device_id *id) 104 + { 105 + struct hid_field *aux1_field, *brightness_field; 106 + struct backlight_properties bl_props = { 0 }; 107 + struct device *dev = &hdev->dev; 108 + struct appletb_bl *bl; 109 + int ret; 110 + 111 + ret = hid_parse(hdev); 112 + if (ret) 113 + return dev_err_probe(dev, ret, "HID parse failed\n"); 114 + 115 + aux1_field = hid_find_field(hdev, HID_FEATURE_REPORT, 116 + HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_AUX1); 117 + 118 + brightness_field = hid_find_field(hdev, HID_FEATURE_REPORT, 119 + HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_BRIGHTNESS); 120 + 121 + if (!aux1_field || !brightness_field) 122 + return -ENODEV; 123 + 124 + if (aux1_field->report != brightness_field->report) 125 + return dev_err_probe(dev, -ENODEV, "Encountered unexpected report structure\n"); 126 + 127 + bl = devm_kzalloc(dev, sizeof(*bl), GFP_KERNEL); 128 + if (!bl) 129 + return -ENOMEM; 130 + 131 + ret = hid_hw_start(hdev, HID_CONNECT_DRIVER); 132 + if (ret) 133 + return dev_err_probe(dev, ret, "HID hardware start failed\n"); 134 + 135 + ret = hid_hw_open(hdev); 136 + if (ret) { 137 + dev_err_probe(dev, ret, "HID hardware open failed\n"); 138 + goto stop_hw; 139 + } 140 + 141 + bl->aux1_field = aux1_field; 142 + bl->brightness_field = brightness_field; 143 + 144 + ret = appletb_bl_set_brightness(bl, 145 + appletb_bl_brightness_map[(appletb_bl_def_brightness > 2) ? 2 : appletb_bl_def_brightness]); 146 + 147 + if (ret) { 148 + dev_err_probe(dev, ret, "Failed to set default touch bar brightness to %d\n", 149 + appletb_bl_def_brightness); 150 + goto close_hw; 151 + } 152 + 153 + bl_props.type = BACKLIGHT_RAW; 154 + bl_props.max_brightness = ARRAY_SIZE(appletb_bl_brightness_map) - 1; 155 + 156 + bl->bdev = devm_backlight_device_register(dev, "appletb_backlight", dev, bl, 157 + &appletb_bl_backlight_ops, &bl_props); 158 + if (IS_ERR(bl->bdev)) { 159 + ret = PTR_ERR(bl->bdev); 160 + dev_err_probe(dev, ret, "Failed to register backlight device\n"); 161 + goto close_hw; 162 + } 163 + 164 + hid_set_drvdata(hdev, bl); 165 + 166 + return 0; 167 + 168 + close_hw: 169 + hid_hw_close(hdev); 170 + stop_hw: 171 + hid_hw_stop(hdev); 172 + 173 + return ret; 174 + } 175 + 176 + static void appletb_bl_remove(struct hid_device *hdev) 177 + { 178 + struct appletb_bl *bl = hid_get_drvdata(hdev); 179 + 180 + appletb_bl_set_brightness(bl, APPLETB_BL_OFF); 181 + 182 + hid_hw_close(hdev); 183 + hid_hw_stop(hdev); 184 + } 185 + 186 + static const struct hid_device_id appletb_bl_hid_ids[] = { 187 + /* MacBook Pro's 2018, 2019, with T2 chip: iBridge DFR Brightness */ 188 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) }, 189 + { } 190 + }; 191 + MODULE_DEVICE_TABLE(hid, appletb_bl_hid_ids); 192 + 193 + static struct hid_driver appletb_bl_hid_driver = { 194 + .name = "hid-appletb-bl", 195 + .id_table = appletb_bl_hid_ids, 196 + .probe = appletb_bl_probe, 197 + .remove = appletb_bl_remove, 198 + }; 199 + module_hid_driver(appletb_bl_hid_driver); 200 + 201 + MODULE_AUTHOR("Ronald Tschalär"); 202 + MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>"); 203 + MODULE_DESCRIPTION("MacBook Pro Touch Bar Backlight driver"); 204 + MODULE_LICENSE("GPL");
+507
drivers/hid/hid-appletb-kbd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Apple Touch Bar Keyboard Mode Driver 4 + * 5 + * Copyright (c) 2017-2018 Ronald Tschalär 6 + * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com> 7 + * Copyright (c) 2024-2025 Aditya Garg <gargaditya08@live.com> 8 + */ 9 + 10 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 + 12 + #include <linux/hid.h> 13 + #include <linux/usb.h> 14 + #include <linux/input.h> 15 + #include <linux/sysfs.h> 16 + #include <linux/bitops.h> 17 + #include <linux/module.h> 18 + #include <linux/string.h> 19 + #include <linux/backlight.h> 20 + #include <linux/timer.h> 21 + #include <linux/input/sparse-keymap.h> 22 + 23 + #include "hid-ids.h" 24 + 25 + #define APPLETB_KBD_MODE_ESC 0 26 + #define APPLETB_KBD_MODE_FN 1 27 + #define APPLETB_KBD_MODE_SPCL 2 28 + #define APPLETB_KBD_MODE_OFF 3 29 + #define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF 30 + 31 + #define APPLETB_DEVID_KEYBOARD 1 32 + #define APPLETB_DEVID_TRACKPAD 2 33 + 34 + #define HID_USAGE_MODE 0x00ff0004 35 + 36 + static int appletb_tb_def_mode = APPLETB_KBD_MODE_SPCL; 37 + module_param_named(mode, appletb_tb_def_mode, int, 0444); 38 + MODULE_PARM_DESC(mode, "Default touchbar mode:\n" 39 + " 0 - escape key only\n" 40 + " 1 - function-keys\n" 41 + " [2] - special keys"); 42 + 43 + static bool appletb_tb_fn_toggle = true; 44 + module_param_named(fntoggle, appletb_tb_fn_toggle, bool, 0644); 45 + MODULE_PARM_DESC(fntoggle, "Switch between Fn and media controls on pressing Fn key"); 46 + 47 + static bool appletb_tb_autodim = true; 48 + module_param_named(autodim, appletb_tb_autodim, bool, 0644); 49 + MODULE_PARM_DESC(autodim, "Automatically dim and turn off the Touch Bar after some time"); 50 + 51 + static int appletb_tb_dim_timeout = 60; 52 + module_param_named(dim_timeout, appletb_tb_dim_timeout, int, 0644); 53 + MODULE_PARM_DESC(dim_timeout, "Dim timeout in sec"); 54 + 55 + static int appletb_tb_idle_timeout = 15; 56 + module_param_named(idle_timeout, appletb_tb_idle_timeout, int, 0644); 57 + MODULE_PARM_DESC(idle_timeout, "Idle timeout in sec"); 58 + 59 + struct appletb_kbd { 60 + struct hid_field *mode_field; 61 + struct input_handler inp_handler; 62 + struct input_handle kbd_handle; 63 + struct input_handle tpd_handle; 64 + struct backlight_device *backlight_dev; 65 + struct timer_list inactivity_timer; 66 + bool has_dimmed; 67 + bool has_turned_off; 68 + u8 saved_mode; 69 + u8 current_mode; 70 + }; 71 + 72 + static const struct key_entry appletb_kbd_keymap[] = { 73 + { KE_KEY, KEY_ESC, { KEY_ESC } }, 74 + { KE_KEY, KEY_F1, { KEY_BRIGHTNESSDOWN } }, 75 + { KE_KEY, KEY_F2, { KEY_BRIGHTNESSUP } }, 76 + { KE_KEY, KEY_F3, { KEY_RESERVED } }, 77 + { KE_KEY, KEY_F4, { KEY_RESERVED } }, 78 + { KE_KEY, KEY_F5, { KEY_KBDILLUMDOWN } }, 79 + { KE_KEY, KEY_F6, { KEY_KBDILLUMUP } }, 80 + { KE_KEY, KEY_F7, { KEY_PREVIOUSSONG } }, 81 + { KE_KEY, KEY_F8, { KEY_PLAYPAUSE } }, 82 + { KE_KEY, KEY_F9, { KEY_NEXTSONG } }, 83 + { KE_KEY, KEY_F10, { KEY_MUTE } }, 84 + { KE_KEY, KEY_F11, { KEY_VOLUMEDOWN } }, 85 + { KE_KEY, KEY_F12, { KEY_VOLUMEUP } }, 86 + { KE_END, 0 } 87 + }; 88 + 89 + static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode) 90 + { 91 + struct hid_report *report = kbd->mode_field->report; 92 + struct hid_device *hdev = report->device; 93 + int ret; 94 + 95 + ret = hid_hw_power(hdev, PM_HINT_FULLON); 96 + if (ret) { 97 + hid_err(hdev, "Device didn't resume (%pe)\n", ERR_PTR(ret)); 98 + return ret; 99 + } 100 + 101 + ret = hid_set_field(kbd->mode_field, 0, mode); 102 + if (ret) { 103 + hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret)); 104 + goto power_normal; 105 + } 106 + 107 + hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 108 + 109 + kbd->current_mode = mode; 110 + 111 + power_normal: 112 + hid_hw_power(hdev, PM_HINT_NORMAL); 113 + 114 + return ret; 115 + } 116 + 117 + static ssize_t mode_show(struct device *dev, 118 + struct device_attribute *attr, char *buf) 119 + { 120 + struct appletb_kbd *kbd = dev_get_drvdata(dev); 121 + 122 + return sysfs_emit(buf, "%d\n", kbd->current_mode); 123 + } 124 + 125 + static ssize_t mode_store(struct device *dev, 126 + struct device_attribute *attr, 127 + const char *buf, size_t size) 128 + { 129 + struct appletb_kbd *kbd = dev_get_drvdata(dev); 130 + u8 mode; 131 + int ret; 132 + 133 + ret = kstrtou8(buf, 0, &mode); 134 + if (ret) 135 + return ret; 136 + 137 + if (mode > APPLETB_KBD_MODE_MAX) 138 + return -EINVAL; 139 + 140 + ret = appletb_kbd_set_mode(kbd, mode); 141 + 142 + return ret < 0 ? ret : size; 143 + } 144 + static DEVICE_ATTR_RW(mode); 145 + 146 + static struct attribute *appletb_kbd_attrs[] = { 147 + &dev_attr_mode.attr, 148 + NULL 149 + }; 150 + ATTRIBUTE_GROUPS(appletb_kbd); 151 + 152 + static int appletb_tb_key_to_slot(unsigned int code) 153 + { 154 + switch (code) { 155 + case KEY_ESC: 156 + return 0; 157 + case KEY_F1 ... KEY_F10: 158 + return code - KEY_F1 + 1; 159 + case KEY_F11 ... KEY_F12: 160 + return code - KEY_F11 + 11; 161 + 162 + default: 163 + return -EINVAL; 164 + } 165 + } 166 + 167 + static void appletb_inactivity_timer(struct timer_list *t) 168 + { 169 + struct appletb_kbd *kbd = from_timer(kbd, t, inactivity_timer); 170 + 171 + if (kbd->backlight_dev && appletb_tb_autodim) { 172 + if (!kbd->has_dimmed) { 173 + backlight_device_set_brightness(kbd->backlight_dev, 1); 174 + kbd->has_dimmed = true; 175 + mod_timer(&kbd->inactivity_timer, jiffies + msecs_to_jiffies(appletb_tb_idle_timeout * 1000)); 176 + } else if (!kbd->has_turned_off) { 177 + backlight_device_set_brightness(kbd->backlight_dev, 0); 178 + kbd->has_turned_off = true; 179 + } 180 + } 181 + } 182 + 183 + static void reset_inactivity_timer(struct appletb_kbd *kbd) 184 + { 185 + if (kbd->backlight_dev && appletb_tb_autodim) { 186 + if (kbd->has_dimmed || kbd->has_turned_off) { 187 + backlight_device_set_brightness(kbd->backlight_dev, 2); 188 + kbd->has_dimmed = false; 189 + kbd->has_turned_off = false; 190 + } 191 + mod_timer(&kbd->inactivity_timer, jiffies + msecs_to_jiffies(appletb_tb_dim_timeout * 1000)); 192 + } 193 + } 194 + 195 + static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *field, 196 + struct hid_usage *usage, __s32 value) 197 + { 198 + struct appletb_kbd *kbd = hid_get_drvdata(hdev); 199 + struct key_entry *translation; 200 + struct input_dev *input; 201 + int slot; 202 + 203 + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD || usage->type != EV_KEY) 204 + return 0; 205 + 206 + input = field->hidinput->input; 207 + 208 + /* 209 + * Skip non-touch-bar keys. 210 + * 211 + * Either the touch bar itself or usbhid generate a slew of key-down 212 + * events for all the meta keys. None of which we're at all interested 213 + * in. 214 + */ 215 + slot = appletb_tb_key_to_slot(usage->code); 216 + if (slot < 0) 217 + return 0; 218 + 219 + reset_inactivity_timer(kbd); 220 + 221 + translation = sparse_keymap_entry_from_scancode(input, usage->code); 222 + 223 + if (translation && kbd->current_mode == APPLETB_KBD_MODE_SPCL) { 224 + input_event(input, usage->type, translation->keycode, value); 225 + 226 + return 1; 227 + } 228 + 229 + return kbd->current_mode == APPLETB_KBD_MODE_OFF; 230 + } 231 + 232 + static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type, 233 + unsigned int code, int value) 234 + { 235 + struct appletb_kbd *kbd = handle->private; 236 + 237 + reset_inactivity_timer(kbd); 238 + 239 + if (type == EV_KEY && code == KEY_FN && appletb_tb_fn_toggle && 240 + (kbd->current_mode == APPLETB_KBD_MODE_SPCL || 241 + kbd->current_mode == APPLETB_KBD_MODE_FN)) { 242 + if (value == 1) { 243 + kbd->saved_mode = kbd->current_mode; 244 + appletb_kbd_set_mode(kbd, kbd->current_mode == APPLETB_KBD_MODE_SPCL 245 + ? APPLETB_KBD_MODE_FN : APPLETB_KBD_MODE_SPCL); 246 + } else if (value == 0) { 247 + if (kbd->saved_mode != kbd->current_mode) 248 + appletb_kbd_set_mode(kbd, kbd->saved_mode); 249 + } 250 + } 251 + } 252 + 253 + static int appletb_kbd_inp_connect(struct input_handler *handler, 254 + struct input_dev *dev, 255 + const struct input_device_id *id) 256 + { 257 + struct appletb_kbd *kbd = handler->private; 258 + struct input_handle *handle; 259 + int rc; 260 + 261 + if (id->driver_info == APPLETB_DEVID_KEYBOARD) { 262 + handle = &kbd->kbd_handle; 263 + handle->name = "tbkbd"; 264 + } else if (id->driver_info == APPLETB_DEVID_TRACKPAD) { 265 + handle = &kbd->tpd_handle; 266 + handle->name = "tbtpd"; 267 + } else { 268 + return -ENOENT; 269 + } 270 + 271 + if (handle->dev) 272 + return -EEXIST; 273 + 274 + handle->open = 0; 275 + handle->dev = input_get_device(dev); 276 + handle->handler = handler; 277 + handle->private = kbd; 278 + 279 + rc = input_register_handle(handle); 280 + if (rc) 281 + goto err_free_dev; 282 + 283 + rc = input_open_device(handle); 284 + if (rc) 285 + goto err_unregister_handle; 286 + 287 + return 0; 288 + 289 + err_unregister_handle: 290 + input_unregister_handle(handle); 291 + err_free_dev: 292 + input_put_device(handle->dev); 293 + handle->dev = NULL; 294 + return rc; 295 + } 296 + 297 + static void appletb_kbd_inp_disconnect(struct input_handle *handle) 298 + { 299 + input_close_device(handle); 300 + input_unregister_handle(handle); 301 + 302 + input_put_device(handle->dev); 303 + handle->dev = NULL; 304 + } 305 + 306 + static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput) 307 + { 308 + int idx; 309 + struct input_dev *input = hidinput->input; 310 + 311 + /* 312 + * Clear various input capabilities that are blindly set by the hid 313 + * driver (usbkbd.c) 314 + */ 315 + memset(input->evbit, 0, sizeof(input->evbit)); 316 + memset(input->keybit, 0, sizeof(input->keybit)); 317 + memset(input->ledbit, 0, sizeof(input->ledbit)); 318 + 319 + __set_bit(EV_REP, input->evbit); 320 + 321 + sparse_keymap_setup(input, appletb_kbd_keymap, NULL); 322 + 323 + for (idx = 0; appletb_kbd_keymap[idx].type != KE_END; idx++) 324 + input_set_capability(input, EV_KEY, appletb_kbd_keymap[idx].code); 325 + 326 + return 0; 327 + } 328 + 329 + static const struct input_device_id appletb_kbd_input_devices[] = { 330 + { 331 + .flags = INPUT_DEVICE_ID_MATCH_BUS | 332 + INPUT_DEVICE_ID_MATCH_VENDOR | 333 + INPUT_DEVICE_ID_MATCH_KEYBIT, 334 + .bustype = BUS_USB, 335 + .vendor = USB_VENDOR_ID_APPLE, 336 + .keybit = { [BIT_WORD(KEY_FN)] = BIT_MASK(KEY_FN) }, 337 + .driver_info = APPLETB_DEVID_KEYBOARD, 338 + }, 339 + { 340 + .flags = INPUT_DEVICE_ID_MATCH_BUS | 341 + INPUT_DEVICE_ID_MATCH_VENDOR | 342 + INPUT_DEVICE_ID_MATCH_KEYBIT, 343 + .bustype = BUS_USB, 344 + .vendor = USB_VENDOR_ID_APPLE, 345 + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, 346 + .driver_info = APPLETB_DEVID_TRACKPAD, 347 + }, 348 + { } 349 + }; 350 + 351 + static bool appletb_kbd_match_internal_device(struct input_handler *handler, 352 + struct input_dev *inp_dev) 353 + { 354 + struct device *dev = &inp_dev->dev; 355 + 356 + /* in kernel: dev && !is_usb_device(dev) */ 357 + while (dev && !(dev->type && dev->type->name && 358 + !strcmp(dev->type->name, "usb_device"))) 359 + dev = dev->parent; 360 + 361 + /* 362 + * Apple labels all their internal keyboards and trackpads as such, 363 + * instead of maintaining an ever expanding list of product-id's we 364 + * just look at the device's product name. 365 + */ 366 + if (dev) 367 + return !!strstr(to_usb_device(dev)->product, "Internal Keyboard"); 368 + 369 + return false; 370 + } 371 + 372 + static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id) 373 + { 374 + struct appletb_kbd *kbd; 375 + struct device *dev = &hdev->dev; 376 + struct hid_field *mode_field; 377 + int ret; 378 + 379 + ret = hid_parse(hdev); 380 + if (ret) 381 + return dev_err_probe(dev, ret, "HID parse failed\n"); 382 + 383 + mode_field = hid_find_field(hdev, HID_OUTPUT_REPORT, 384 + HID_GD_KEYBOARD, HID_USAGE_MODE); 385 + if (!mode_field) 386 + return -ENODEV; 387 + 388 + kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL); 389 + if (!kbd) 390 + return -ENOMEM; 391 + 392 + kbd->mode_field = mode_field; 393 + 394 + ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT); 395 + if (ret) 396 + return dev_err_probe(dev, ret, "HID hw start failed\n"); 397 + 398 + ret = hid_hw_open(hdev); 399 + if (ret) { 400 + dev_err_probe(dev, ret, "HID hw open failed\n"); 401 + goto stop_hw; 402 + } 403 + 404 + kbd->backlight_dev = backlight_device_get_by_name("appletb_backlight"); 405 + if (!kbd->backlight_dev) { 406 + dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n"); 407 + } else { 408 + backlight_device_set_brightness(kbd->backlight_dev, 2); 409 + timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0); 410 + mod_timer(&kbd->inactivity_timer, jiffies + msecs_to_jiffies(appletb_tb_dim_timeout * 1000)); 411 + } 412 + 413 + kbd->inp_handler.event = appletb_kbd_inp_event; 414 + kbd->inp_handler.connect = appletb_kbd_inp_connect; 415 + kbd->inp_handler.disconnect = appletb_kbd_inp_disconnect; 416 + kbd->inp_handler.name = "appletb"; 417 + kbd->inp_handler.id_table = appletb_kbd_input_devices; 418 + kbd->inp_handler.match = appletb_kbd_match_internal_device; 419 + kbd->inp_handler.private = kbd; 420 + 421 + ret = input_register_handler(&kbd->inp_handler); 422 + if (ret) { 423 + dev_err_probe(dev, ret, "Unable to register keyboard handler\n"); 424 + goto close_hw; 425 + } 426 + 427 + ret = appletb_kbd_set_mode(kbd, appletb_tb_def_mode); 428 + if (ret) { 429 + dev_err_probe(dev, ret, "Failed to set touchbar mode\n"); 430 + goto close_hw; 431 + } 432 + 433 + hid_set_drvdata(hdev, kbd); 434 + 435 + return 0; 436 + 437 + close_hw: 438 + hid_hw_close(hdev); 439 + stop_hw: 440 + hid_hw_stop(hdev); 441 + return ret; 442 + } 443 + 444 + static void appletb_kbd_remove(struct hid_device *hdev) 445 + { 446 + struct appletb_kbd *kbd = hid_get_drvdata(hdev); 447 + 448 + appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); 449 + 450 + input_unregister_handler(&kbd->inp_handler); 451 + del_timer_sync(&kbd->inactivity_timer); 452 + 453 + hid_hw_close(hdev); 454 + hid_hw_stop(hdev); 455 + } 456 + 457 + #ifdef CONFIG_PM 458 + static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) 459 + { 460 + struct appletb_kbd *kbd = hid_get_drvdata(hdev); 461 + 462 + kbd->saved_mode = kbd->current_mode; 463 + appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); 464 + 465 + return 0; 466 + } 467 + 468 + static int appletb_kbd_reset_resume(struct hid_device *hdev) 469 + { 470 + struct appletb_kbd *kbd = hid_get_drvdata(hdev); 471 + 472 + appletb_kbd_set_mode(kbd, kbd->saved_mode); 473 + 474 + return 0; 475 + } 476 + #endif 477 + 478 + static const struct hid_device_id appletb_kbd_hid_ids[] = { 479 + /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */ 480 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, 481 + { } 482 + }; 483 + MODULE_DEVICE_TABLE(hid, appletb_kbd_hid_ids); 484 + 485 + static struct hid_driver appletb_kbd_hid_driver = { 486 + .name = "hid-appletb-kbd", 487 + .id_table = appletb_kbd_hid_ids, 488 + .probe = appletb_kbd_probe, 489 + .remove = appletb_kbd_remove, 490 + .event = appletb_kbd_hid_event, 491 + .input_configured = appletb_kbd_input_configured, 492 + #ifdef CONFIG_PM 493 + .suspend = appletb_kbd_suspend, 494 + .reset_resume = appletb_kbd_reset_resume, 495 + #endif 496 + .driver.dev_groups = appletb_kbd_groups, 497 + }; 498 + module_hid_driver(appletb_kbd_hid_driver); 499 + 500 + /* The backlight driver should be loaded before the keyboard driver is initialised */ 501 + MODULE_SOFTDEP("pre: hid_appletb_bl"); 502 + 503 + MODULE_AUTHOR("Ronald Tschalär"); 504 + MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>"); 505 + MODULE_AUTHOR("Aditya Garg <gargaditya08@live.com>"); 506 + MODULE_DESCRIPTION("MacBook Pro Touch Bar Keyboard Mode driver"); 507 + MODULE_LICENSE("GPL");
+5 -1
drivers/hid/hid-core.c
··· 657 657 ret = hid_add_field(parser, HID_FEATURE_REPORT, data); 658 658 break; 659 659 default: 660 - hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag); 660 + if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN && 661 + item->tag <= HID_MAIN_ITEM_TAG_RESERVED_MAX) 662 + hid_warn(parser->device, "reserved main item tag 0x%x\n", item->tag); 663 + else 664 + hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag); 661 665 ret = 0; 662 666 } 663 667
-1
drivers/hid/hid-google-hammer.c
··· 22 22 #include <linux/platform_data/cros_ec_commands.h> 23 23 #include <linux/platform_data/cros_ec_proto.h> 24 24 #include <linux/platform_device.h> 25 - #include <linux/pm_wakeup.h> 26 25 #include <linux/unaligned.h> 27 26 28 27 #include "hid-ids.h"
+37
drivers/hid/hid-ids.h
··· 190 190 #define USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT 0x8102 191 191 #define USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY 0x8302 192 192 193 + #define USB_VENDOR_ID_ASETEK 0x2433 194 + #define USB_DEVICE_ID_ASETEK_INVICTA 0xf300 195 + #define USB_DEVICE_ID_ASETEK_FORTE 0xf301 196 + #define USB_DEVICE_ID_ASETEK_LA_PRIMA 0xf303 197 + #define USB_DEVICE_ID_ASETEK_TONY_KANAAN 0xf306 198 + 193 199 #define USB_VENDOR_ID_ASUS 0x0486 194 200 #define USB_DEVICE_ID_ASUS_T91MT 0x0185 195 201 #define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186 ··· 267 261 #define USB_VENDOR_ID_BTC 0x046e 268 262 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 269 263 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 264 + 265 + #define USB_VENDOR_ID_CAMMUS 0x3416 266 + #define USB_DEVICE_ID_CAMMUS_C5 0x0301 267 + #define USB_DEVICE_ID_CAMMUS_C12 0x0302 270 268 271 269 #define USB_VENDOR_ID_CANDO 0x2087 272 270 #define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 ··· 462 452 463 453 #define USB_VENDOR_ID_EVISION 0x320f 464 454 #define USB_DEVICE_ID_EVISION_ICL01 0x5041 455 + 456 + #define USB_VENDOR_ID_FFBEAST 0x045b 457 + #define USB_DEVICE_ID_FFBEAST_JOYSTICK 0x58f9 458 + #define USB_DEVICE_ID_FFBEAST_RUDDER 0x5968 459 + #define USB_DEVICE_ID_FFBEAST_WHEEL 0x59d7 465 460 466 461 #define USB_VENDOR_ID_FLATFROG 0x25b5 467 462 #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 ··· 832 817 #define I2C_DEVICE_ID_LG_8001 0x8001 833 818 #define I2C_DEVICE_ID_LG_7010 0x7010 834 819 820 + #define USB_VENDOR_ID_LITE_STAR 0x11ff 821 + #define USB_DEVICE_ID_PXN_V10 0x3245 822 + #define USB_DEVICE_ID_PXN_V12 0x1212 823 + #define USB_DEVICE_ID_PXN_V12_LITE 0x1112 824 + #define USB_DEVICE_ID_PXN_V12_LITE_2 0x1211 825 + #define USB_DEVICE_LITE_STAR_GT987_FF 0x2141 826 + 835 827 #define USB_VENDOR_ID_LOGITECH 0x046d 836 828 #define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07 837 829 #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e ··· 985 963 986 964 #define USB_VENDOR_ID_MONTEREY 0x0566 987 965 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 966 + 967 + #define USB_VENDOR_ID_MOZA 0x346e 968 + #define USB_DEVICE_ID_MOZA_R3 0x0005 969 + #define USB_DEVICE_ID_MOZA_R3_2 0x0015 970 + #define USB_DEVICE_ID_MOZA_R5 0x0004 971 + #define USB_DEVICE_ID_MOZA_R5_2 0x0014 972 + #define USB_DEVICE_ID_MOZA_R9 0x0002 973 + #define USB_DEVICE_ID_MOZA_R9_2 0x0012 974 + #define USB_DEVICE_ID_MOZA_R12 0x0006 975 + #define USB_DEVICE_ID_MOZA_R12_2 0x0016 976 + #define USB_DEVICE_ID_MOZA_R16_R21 0x0000 977 + #define USB_DEVICE_ID_MOZA_R16_R21_2 0x0010 988 978 989 979 #define USB_VENDOR_ID_MSI 0x1770 990 980 #define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 ··· 1410 1376 #define USB_DEVICE_ID_VELLEMAN_K8055_LAST 0x5503 1411 1377 #define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 1412 1378 #define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 1379 + 1380 + #define USB_VENDOR_ID_VRS 0x0483 1381 + #define USB_DEVICE_ID_VRS_DFP 0xa355 1413 1382 1414 1383 #define USB_VENDOR_ID_VTL 0x0306 1415 1384 #define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f
+3 -5
drivers/hid/hid-lenovo.c
··· 728 728 if (hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) { 729 729 report_key_event(input, KEY_RFKILL); 730 730 return 1; 731 - } else { 732 - platform_profile_cycle(); 733 - return 1; 734 731 } 735 - return 0; 732 + platform_profile_cycle(); 733 + return 1; 736 734 case TP_X12_RAW_HOTKEY_FN_F10: 737 735 /* TAB1 has PICKUP Phone and TAB2 use Snipping tool*/ 738 736 (hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB) ? ··· 776 778 if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB 777 779 || hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2) 778 780 && size >= 3 && report->id == 0x03)) 779 - return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(u32 *)data)); 781 + return lenovo_raw_event_TP_X12_tab(hdev, le32_to_cpu(*(__le32 *)data)); 780 782 781 783 return 0; 782 784 }
+65 -81
drivers/hid/hid-lg-g15.c
··· 8 8 #include <linux/device.h> 9 9 #include <linux/hid.h> 10 10 #include <linux/leds.h> 11 + #include <linux/led-class-multicolor.h> 11 12 #include <linux/module.h> 12 13 #include <linux/random.h> 13 14 #include <linux/sched.h> 14 15 #include <linux/usb.h> 15 16 #include <linux/wait.h> 17 + #include <dt-bindings/leds/common.h> 16 18 17 19 #include "hid-ids.h" 18 20 ··· 46 44 }; 47 45 48 46 struct lg_g15_led { 49 - struct led_classdev cdev; 47 + union { 48 + struct led_classdev cdev; 49 + struct led_classdev_mc mcdev; 50 + }; 50 51 enum led_brightness brightness; 51 52 enum lg_g15_led_type led; 53 + /* Used to store initial color intensities before subled_info is allocated */ 52 54 u8 red, green, blue; 53 55 }; 54 56 ··· 235 229 struct lg_g15_led *g15_led, 236 230 enum led_brightness brightness) 237 231 { 232 + struct mc_subled *subleds = g15_led->mcdev.subled_info; 238 233 int ret; 239 234 235 + led_mc_calc_color_components(&g15_led->mcdev, brightness); 236 + 240 237 g15->transfer_buf[0] = 5 + g15_led->led; 241 - g15->transfer_buf[1] = 242 - DIV_ROUND_CLOSEST(g15_led->red * brightness, 255); 243 - g15->transfer_buf[2] = 244 - DIV_ROUND_CLOSEST(g15_led->green * brightness, 255); 245 - g15->transfer_buf[3] = 246 - DIV_ROUND_CLOSEST(g15_led->blue * brightness, 255); 238 + g15->transfer_buf[1] = subleds[0].brightness; 239 + g15->transfer_buf[2] = subleds[1].brightness; 240 + g15->transfer_buf[3] = subleds[2].brightness; 247 241 248 242 ret = hid_hw_raw_request(g15->hdev, 249 243 LG_G510_FEATURE_BACKLIGHT_RGB + g15_led->led, ··· 264 258 static int lg_g510_kbd_led_set(struct led_classdev *led_cdev, 265 259 enum led_brightness brightness) 266 260 { 261 + struct led_classdev_mc *mc = lcdev_to_mccdev(led_cdev); 267 262 struct lg_g15_led *g15_led = 268 - container_of(led_cdev, struct lg_g15_led, cdev); 263 + container_of(mc, struct lg_g15_led, mcdev); 269 264 struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent); 270 265 int ret; 271 266 ··· 283 276 284 277 static enum led_brightness lg_g510_kbd_led_get(struct led_classdev *led_cdev) 285 278 { 279 + struct led_classdev_mc *mc = lcdev_to_mccdev(led_cdev); 286 280 struct lg_g15_led *g15_led = 287 - container_of(led_cdev, struct lg_g15_led, cdev); 281 + container_of(mc, struct lg_g15_led, mcdev); 288 282 289 283 return g15_led->brightness; 290 284 } 291 285 292 - static ssize_t color_store(struct device *dev, struct device_attribute *attr, 293 - const char *buf, size_t count) 294 - { 295 - struct led_classdev *led_cdev = dev_get_drvdata(dev); 296 - struct lg_g15_led *g15_led = 297 - container_of(led_cdev, struct lg_g15_led, cdev); 298 - struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent); 299 - unsigned long value; 300 - int ret; 301 - 302 - if (count < 7 || (count == 8 && buf[7] != '\n') || count > 8) 303 - return -EINVAL; 304 - 305 - if (buf[0] != '#') 306 - return -EINVAL; 307 - 308 - ret = kstrtoul(buf + 1, 16, &value); 309 - if (ret) 310 - return ret; 311 - 312 - mutex_lock(&g15->mutex); 313 - g15_led->red = (value & 0xff0000) >> 16; 314 - g15_led->green = (value & 0x00ff00) >> 8; 315 - g15_led->blue = (value & 0x0000ff); 316 - ret = lg_g510_kbd_led_write(g15, g15_led, g15_led->brightness); 317 - mutex_unlock(&g15->mutex); 318 - 319 - return (ret < 0) ? ret : count; 320 - } 321 - 322 - static ssize_t color_show(struct device *dev, struct device_attribute *attr, 323 - char *buf) 324 - { 325 - struct led_classdev *led_cdev = dev_get_drvdata(dev); 326 - struct lg_g15_led *g15_led = 327 - container_of(led_cdev, struct lg_g15_led, cdev); 328 - struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent); 329 - ssize_t ret; 330 - 331 - mutex_lock(&g15->mutex); 332 - ret = sprintf(buf, "#%02x%02x%02x\n", 333 - g15_led->red, g15_led->green, g15_led->blue); 334 - mutex_unlock(&g15->mutex); 335 - 336 - return ret; 337 - } 338 - 339 - static DEVICE_ATTR_RW(color); 340 - 341 - static struct attribute *lg_g510_kbd_led_attrs[] = { 342 - &dev_attr_color.attr, 343 - NULL, 344 - }; 345 - 346 - static const struct attribute_group lg_g510_kbd_led_group = { 347 - .attrs = lg_g510_kbd_led_attrs, 348 - }; 349 - 350 - static const struct attribute_group *lg_g510_kbd_led_groups[] = { 351 - &lg_g510_kbd_led_group, 352 - NULL, 353 - }; 354 - 355 286 static void lg_g510_leds_sync_work(struct work_struct *work) 356 287 { 357 288 struct lg_g15_data *g15 = container_of(work, struct lg_g15_data, work); 289 + struct lg_g15_led *g15_led = &g15->leds[LG_G15_KBD_BRIGHTNESS]; 358 290 359 291 mutex_lock(&g15->mutex); 360 - lg_g510_kbd_led_write(g15, &g15->leds[LG_G15_KBD_BRIGHTNESS], 361 - g15->leds[LG_G15_KBD_BRIGHTNESS].brightness); 292 + lg_g510_kbd_led_write(g15, g15_led, g15_led->brightness); 362 293 mutex_unlock(&g15->mutex); 363 294 } 364 295 ··· 612 667 hid_hw_close(hdev); 613 668 } 614 669 670 + static void lg_g15_setup_led_rgb(struct lg_g15_data *g15, int index) 671 + { 672 + int i; 673 + struct mc_subled *subled_info; 674 + 675 + g15->leds[index].mcdev.led_cdev.brightness_set_blocking = 676 + lg_g510_kbd_led_set; 677 + g15->leds[index].mcdev.led_cdev.brightness_get = 678 + lg_g510_kbd_led_get; 679 + g15->leds[index].mcdev.led_cdev.max_brightness = 255; 680 + g15->leds[index].mcdev.num_colors = 3; 681 + 682 + subled_info = devm_kcalloc(&g15->hdev->dev, 3, sizeof(*subled_info), GFP_KERNEL); 683 + if (!subled_info) 684 + return; 685 + 686 + for (i = 0; i < 3; i++) { 687 + switch (i + 1) { 688 + case LED_COLOR_ID_RED: 689 + subled_info[i].color_index = LED_COLOR_ID_RED; 690 + subled_info[i].intensity = g15->leds[index].red; 691 + break; 692 + case LED_COLOR_ID_GREEN: 693 + subled_info[i].color_index = LED_COLOR_ID_GREEN; 694 + subled_info[i].intensity = g15->leds[index].green; 695 + break; 696 + case LED_COLOR_ID_BLUE: 697 + subled_info[i].color_index = LED_COLOR_ID_BLUE; 698 + subled_info[i].intensity = g15->leds[index].blue; 699 + break; 700 + } 701 + subled_info[i].channel = i; 702 + } 703 + g15->leds[index].mcdev.subled_info = subled_info; 704 + } 705 + 615 706 static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name) 616 707 { 708 + int ret; 709 + 617 710 g15->leds[i].led = i; 618 711 g15->leds[i].cdev.name = name; 619 712 ··· 668 685 } else { 669 686 g15->leds[i].cdev.max_brightness = 1; 670 687 } 688 + ret = devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev); 671 689 break; 672 690 case LG_G510: 673 691 case LG_G510_USB_AUDIO: ··· 681 697 g15->leds[i].cdev.name = "g15::power_on_backlight_val"; 682 698 fallthrough; 683 699 case LG_G15_KBD_BRIGHTNESS: 684 - g15->leds[i].cdev.brightness_set_blocking = 685 - lg_g510_kbd_led_set; 686 - g15->leds[i].cdev.brightness_get = 687 - lg_g510_kbd_led_get; 688 - g15->leds[i].cdev.max_brightness = 255; 689 - g15->leds[i].cdev.groups = lg_g510_kbd_led_groups; 700 + /* register multicolor LED */ 701 + lg_g15_setup_led_rgb(g15, i); 702 + ret = devm_led_classdev_multicolor_register_ext(&g15->hdev->dev, 703 + &g15->leds[i].mcdev, 704 + NULL); 690 705 break; 691 706 default: 692 707 g15->leds[i].cdev.brightness_set_blocking = ··· 693 710 g15->leds[i].cdev.brightness_get = 694 711 lg_g510_mkey_led_get; 695 712 g15->leds[i].cdev.max_brightness = 1; 713 + ret = devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev); 696 714 } 697 715 break; 698 716 } 699 717 700 - return devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev); 718 + return ret; 701 719 } 702 720 703 721 /* Common input device init code shared between keyboards and Z-10 speaker handling */
+67 -77
drivers/hid/hid-plantronics.c
··· 6 6 * Copyright (c) 2015-2018 Terry Junge <terry.junge@plantronics.com> 7 7 */ 8 8 9 - /* 10 - */ 11 - 12 9 #include "hid-ids.h" 13 10 14 11 #include <linux/hid.h> ··· 20 23 21 24 #define PLT_VOL_UP 0x00b1 22 25 #define PLT_VOL_DOWN 0x00b2 26 + #define PLT_MIC_MUTE 0x00b5 23 27 24 28 #define PLT1_VOL_UP (PLT_HID_1_0_PAGE | PLT_VOL_UP) 25 29 #define PLT1_VOL_DOWN (PLT_HID_1_0_PAGE | PLT_VOL_DOWN) 30 + #define PLT1_MIC_MUTE (PLT_HID_1_0_PAGE | PLT_MIC_MUTE) 26 31 #define PLT2_VOL_UP (PLT_HID_2_0_PAGE | PLT_VOL_UP) 27 32 #define PLT2_VOL_DOWN (PLT_HID_2_0_PAGE | PLT_VOL_DOWN) 33 + #define PLT2_MIC_MUTE (PLT_HID_2_0_PAGE | PLT_MIC_MUTE) 34 + #define HID_TELEPHONY_MUTE (HID_UP_TELEPHONY | 0x2f) 35 + #define HID_CONSUMER_MUTE (HID_UP_CONSUMER | 0xe2) 28 36 29 37 #define PLT_DA60 0xda60 30 38 #define PLT_BT300_MIN 0x0413 31 39 #define PLT_BT300_MAX 0x0418 32 40 33 - 34 - #define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \ 35 - (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) 36 - 37 - #define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0) 38 - #define PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS BIT(1) 39 - 40 41 #define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */ 41 - #define PLT_FOLLOWED_OPPOSITE_KEY_TIMEOUT 220 /* ms */ 42 42 43 43 struct plt_drv_data { 44 44 unsigned long device_type; 45 - unsigned long last_volume_key_ts; 46 - u32 quirks; 45 + unsigned long last_key_ts; 46 + unsigned long double_key_to; 47 + __u16 last_key; 47 48 }; 48 49 49 50 static int plantronics_input_mapping(struct hid_device *hdev, ··· 53 58 unsigned short mapped_key; 54 59 struct plt_drv_data *drv_data = hid_get_drvdata(hdev); 55 60 unsigned long plt_type = drv_data->device_type; 61 + int allow_mute = usage->hid == HID_TELEPHONY_MUTE; 62 + int allow_consumer = field->application == HID_CP_CONSUMERCONTROL && 63 + (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && 64 + usage->hid != HID_CONSUMER_MUTE; 56 65 57 66 /* special case for PTT products */ 58 67 if (field->application == HID_GD_JOYSTICK) 59 68 goto defaulted; 60 69 61 - /* handle volume up/down mapping */ 62 70 /* non-standard types or multi-HID interfaces - plt_type is PID */ 63 71 if (!(plt_type & HID_USAGE_PAGE)) { 64 72 switch (plt_type) { 65 73 case PLT_DA60: 66 - if (PLT_ALLOW_CONSUMER) 74 + if (allow_consumer) 67 75 goto defaulted; 68 - goto ignored; 76 + if (usage->hid == HID_CONSUMER_MUTE) { 77 + mapped_key = KEY_MICMUTE; 78 + goto mapped; 79 + } 80 + break; 69 81 default: 70 - if (PLT_ALLOW_CONSUMER) 82 + if (allow_consumer || allow_mute) 71 83 goto defaulted; 72 84 } 85 + goto ignored; 73 86 } 74 - /* handle standard types - plt_type is 0xffa0uuuu or 0xffa2uuuu */ 75 - /* 'basic telephony compliant' - allow default consumer page map */ 76 - else if ((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY && 77 - (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) { 78 - if (PLT_ALLOW_CONSUMER) 79 - goto defaulted; 80 - } 81 - /* not 'basic telephony' - apply legacy mapping */ 82 - /* only map if the field is in the device's primary vendor page */ 83 - else if (!((field->application ^ plt_type) & HID_USAGE_PAGE)) { 87 + 88 + /* handle standard consumer control mapping */ 89 + /* and standard telephony mic mute mapping */ 90 + if (allow_consumer || allow_mute) 91 + goto defaulted; 92 + 93 + /* handle vendor unique types - plt_type is 0xffa0uuuu or 0xffa2uuuu */ 94 + /* if not 'basic telephony compliant' - map vendor unique controls */ 95 + if (!((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY && 96 + (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) && 97 + !((field->application ^ plt_type) & HID_USAGE_PAGE)) 84 98 switch (usage->hid) { 85 99 case PLT1_VOL_UP: 86 100 case PLT2_VOL_UP: ··· 99 95 case PLT2_VOL_DOWN: 100 96 mapped_key = KEY_VOLUMEDOWN; 101 97 goto mapped; 98 + case PLT1_MIC_MUTE: 99 + case PLT2_MIC_MUTE: 100 + mapped_key = KEY_MICMUTE; 101 + goto mapped; 102 102 } 103 - } 104 103 105 104 /* 106 105 * Future mapping of call control or other usages, ··· 112 105 */ 113 106 114 107 ignored: 108 + hid_dbg(hdev, "usage: %08x (appl: %08x) - ignored\n", 109 + usage->hid, field->application); 115 110 return -1; 116 111 117 112 defaulted: ··· 132 123 struct hid_usage *usage, __s32 value) 133 124 { 134 125 struct plt_drv_data *drv_data = hid_get_drvdata(hdev); 126 + unsigned long prev_tsto, cur_ts; 127 + __u16 prev_key, cur_key; 135 128 136 - if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) { 137 - unsigned long prev_ts, cur_ts; 129 + /* Usages are filtered in plantronics_usages. */ 138 130 139 - /* Usages are filtered in plantronics_usages. */ 131 + /* HZ too low for ms resolution - double key detection disabled */ 132 + /* or it is a key release - handle key presses only. */ 133 + if (!drv_data->double_key_to || !value) 134 + return 0; 140 135 141 - if (!value) /* Handle key presses only. */ 142 - return 0; 136 + prev_tsto = drv_data->last_key_ts + drv_data->double_key_to; 137 + cur_ts = drv_data->last_key_ts = jiffies; 138 + prev_key = drv_data->last_key; 139 + cur_key = drv_data->last_key = usage->code; 143 140 144 - prev_ts = drv_data->last_volume_key_ts; 145 - cur_ts = jiffies; 146 - if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT) 147 - return 1; /* Ignore the repeated key. */ 148 - 149 - drv_data->last_volume_key_ts = cur_ts; 141 + /* If the same key occurs in <= double_key_to -- ignore it */ 142 + if (prev_key == cur_key && time_before_eq(cur_ts, prev_tsto)) { 143 + hid_dbg(hdev, "double key %d ignored\n", cur_key); 144 + return 1; /* Ignore the repeated key. */ 150 145 } 151 - if (drv_data->quirks & PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS) { 152 - unsigned long prev_ts, cur_ts; 153 - 154 - /* Usages are filtered in plantronics_usages. */ 155 - 156 - if (!value) /* Handle key presses only. */ 157 - return 0; 158 - 159 - prev_ts = drv_data->last_volume_key_ts; 160 - cur_ts = jiffies; 161 - if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_FOLLOWED_OPPOSITE_KEY_TIMEOUT) 162 - return 1; /* Ignore the followed opposite volume key. */ 163 - 164 - drv_data->last_volume_key_ts = cur_ts; 165 - } 166 - 167 146 return 0; 168 147 } 169 148 ··· 193 196 ret = hid_parse(hdev); 194 197 if (ret) { 195 198 hid_err(hdev, "parse failed\n"); 196 - goto err; 199 + return ret; 197 200 } 198 201 199 202 drv_data->device_type = plantronics_device_type(hdev); 200 - drv_data->quirks = id->driver_data; 201 - drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT); 203 + drv_data->double_key_to = msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT); 204 + drv_data->last_key_ts = jiffies - drv_data->double_key_to; 205 + 206 + /* if HZ does not allow ms resolution - disable double key detection */ 207 + if (drv_data->double_key_to < PLT_DOUBLE_KEY_TIMEOUT) 208 + drv_data->double_key_to = 0; 202 209 203 210 hid_set_drvdata(hdev, drv_data); 204 211 ··· 211 210 if (ret) 212 211 hid_err(hdev, "hw start failed\n"); 213 212 214 - err: 215 213 return ret; 216 214 } 217 215 218 216 static const struct hid_device_id plantronics_devices[] = { 219 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 220 - USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3210_SERIES), 221 - .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, 222 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 223 - USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES), 224 - .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, 225 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 226 - USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3215_SERIES), 227 - .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, 228 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 229 - USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3225_SERIES), 230 - .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, 231 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 232 - USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3325_SERIES), 233 - .driver_data = PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS }, 234 - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, 235 - USB_DEVICE_ID_PLANTRONICS_ENCOREPRO_500_SERIES), 236 - .driver_data = PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS }, 237 217 { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, 238 218 { } 239 219 }; ··· 223 241 static const struct hid_usage_id plantronics_usages[] = { 224 242 { HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID }, 225 243 { HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID }, 244 + { HID_TELEPHONY_MUTE, EV_KEY, HID_ANY_ID }, 245 + { HID_CONSUMER_MUTE, EV_KEY, HID_ANY_ID }, 246 + { PLT2_VOL_UP, EV_KEY, HID_ANY_ID }, 247 + { PLT2_VOL_DOWN, EV_KEY, HID_ANY_ID }, 248 + { PLT2_MIC_MUTE, EV_KEY, HID_ANY_ID }, 249 + { PLT1_VOL_UP, EV_KEY, HID_ANY_ID }, 250 + { PLT1_VOL_DOWN, EV_KEY, HID_ANY_ID }, 251 + { PLT1_MIC_MUTE, EV_KEY, HID_ANY_ID }, 226 252 { HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR } 227 253 }; 228 254
+17 -7
drivers/hid/hid-quirks.c
··· 328 328 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, 329 329 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) }, 330 330 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) }, 331 - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) }, 332 - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, 333 331 #endif 334 332 #if IS_ENABLED(CONFIG_HID_APPLEIR) 335 333 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, ··· 335 337 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, 336 338 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, 337 339 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, 340 + #endif 341 + #if IS_ENABLED(CONFIG_HID_APPLETB_BL) 342 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) }, 343 + #endif 344 + #if IS_ENABLED(CONFIG_HID_APPLETB_KBD) 345 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, 338 346 #endif 339 347 #if IS_ENABLED(CONFIG_HID_ASUS) 340 348 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) }, ··· 599 595 #if IS_ENABLED(CONFIG_HID_PLANTRONICS) 600 596 { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, 601 597 #endif 598 + #if IS_ENABLED(CONFIG_HID_PLAYSTATION) 599 + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, 600 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, 601 + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, 602 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, 603 + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) }, 604 + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, 605 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, 606 + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, 607 + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, 608 + #endif 602 609 #if IS_ENABLED(CONFIG_HID_PRIMAX) 603 610 { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, 604 611 #endif ··· 679 664 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, 680 665 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 681 666 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 682 - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, 683 - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, 684 - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, 685 - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, 686 - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) }, 687 667 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, 688 668 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, 689 669 { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) },
+2 -5
drivers/hid/hid-steam.c
··· 559 559 if (steam->gamepad_mode) 560 560 enable = false; 561 561 562 + mutex_lock(&steam->report_mutex); 562 563 if (enable) { 563 - mutex_lock(&steam->report_mutex); 564 564 /* enable esc, enter, cursors */ 565 565 steam_send_report_byte(steam, ID_SET_DEFAULT_DIGITAL_MAPPINGS); 566 566 /* reset settings */ 567 567 steam_send_report_byte(steam, ID_LOAD_DEFAULT_SETTINGS); 568 - mutex_unlock(&steam->report_mutex); 569 568 } else { 570 - mutex_lock(&steam->report_mutex); 571 569 /* disable esc, enter, cursor */ 572 570 steam_send_report_byte(steam, ID_CLEAR_DIGITAL_MAPPINGS); 573 571 ··· 577 579 SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */ 578 580 SETTING_STEAM_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ 579 581 0); 580 - mutex_unlock(&steam->report_mutex); 581 582 } else { 582 583 steam_write_settings(steam, 583 584 SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 584 585 SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ 585 586 0); 586 - mutex_unlock(&steam->report_mutex); 587 587 } 588 588 } 589 + mutex_unlock(&steam->report_mutex); 589 590 } 590 591 591 592 static int steam_input_open(struct input_dev *dev)
+202
drivers/hid/hid-universal-pidff.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * HID UNIVERSAL PIDFF 4 + * hid-pidff wrapper for PID-enabled devices 5 + * Handles device reports, quirks and extends usable button range 6 + * 7 + * Copyright (c) 2024, 2025 Oleg Makarenko 8 + * Copyright (c) 2024, 2025 Tomasz Pakuła 9 + */ 10 + 11 + #include <linux/device.h> 12 + #include <linux/hid.h> 13 + #include <linux/module.h> 14 + #include <linux/input-event-codes.h> 15 + #include "hid-ids.h" 16 + #include "usbhid/hid-pidff.h" 17 + 18 + #define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1) 19 + 20 + /* 21 + * Map buttons manually to extend the default joystick button limit 22 + */ 23 + static int universal_pidff_input_mapping(struct hid_device *hdev, 24 + struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, 25 + unsigned long **bit, int *max) 26 + { 27 + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) 28 + return 0; 29 + 30 + if (field->application != HID_GD_JOYSTICK) 31 + return 0; 32 + 33 + int button = ((usage->hid - 1) & HID_USAGE); 34 + int code = button + BTN_JOYSTICK; 35 + 36 + /* Detect the end of JOYSTICK buttons range */ 37 + if (code > BTN_DEAD) 38 + code = button + KEY_NEXT_FAVORITE - JOY_RANGE; 39 + 40 + /* 41 + * Map overflowing buttons to KEY_RESERVED to not ignore 42 + * them and let them still trigger MSC_SCAN 43 + */ 44 + if (code > KEY_MAX) 45 + code = KEY_RESERVED; 46 + 47 + hid_map_usage(hi, usage, bit, max, EV_KEY, code); 48 + hid_dbg(hdev, "Button %d: usage %d", button, code); 49 + return 1; 50 + } 51 + 52 + /* 53 + * Check if the device is PID and initialize it 54 + * Add quirks after initialisation 55 + */ 56 + static int universal_pidff_probe(struct hid_device *hdev, 57 + const struct hid_device_id *id) 58 + { 59 + int i, error; 60 + error = hid_parse(hdev); 61 + if (error) { 62 + hid_err(hdev, "HID parse failed\n"); 63 + goto err; 64 + } 65 + 66 + error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 67 + if (error) { 68 + hid_err(hdev, "HID hw start failed\n"); 69 + goto err; 70 + } 71 + 72 + /* Check if device contains PID usage page */ 73 + error = 1; 74 + for (i = 0; i < hdev->collection_size; i++) 75 + if ((hdev->collection[i].usage & HID_USAGE_PAGE) == HID_UP_PID) { 76 + error = 0; 77 + hid_dbg(hdev, "PID usage page found\n"); 78 + break; 79 + } 80 + 81 + /* 82 + * Do not fail as this might be the second "device" 83 + * just for additional buttons/axes. Exit cleanly if force 84 + * feedback usage page wasn't found (included devices were 85 + * tested and confirmed to be USB PID after all). 86 + */ 87 + if (error) { 88 + hid_dbg(hdev, "PID usage page not found in the descriptor\n"); 89 + return 0; 90 + } 91 + 92 + /* Check if HID_PID support is enabled */ 93 + int (*init_function)(struct hid_device *, u32); 94 + init_function = hid_pidff_init_with_quirks; 95 + 96 + if (!init_function) { 97 + hid_warn(hdev, "HID_PID support not enabled!\n"); 98 + return 0; 99 + } 100 + 101 + error = init_function(hdev, id->driver_data); 102 + if (error) { 103 + hid_warn(hdev, "Error initialising force feedback\n"); 104 + goto err; 105 + } 106 + 107 + hid_info(hdev, "Universal pidff driver loaded successfully!"); 108 + 109 + return 0; 110 + err: 111 + return error; 112 + } 113 + 114 + static int universal_pidff_input_configured(struct hid_device *hdev, 115 + struct hid_input *hidinput) 116 + { 117 + int axis; 118 + struct input_dev *input = hidinput->input; 119 + 120 + if (!input->absinfo) 121 + return 0; 122 + 123 + /* Decrease fuzz and deadzone on available axes */ 124 + for (axis = ABS_X; axis <= ABS_BRAKE; axis++) { 125 + if (!test_bit(axis, input->absbit)) 126 + continue; 127 + 128 + input_set_abs_params(input, axis, 129 + input->absinfo[axis].minimum, 130 + input->absinfo[axis].maximum, 131 + axis == ABS_X ? 0 : 8, 0); 132 + } 133 + 134 + /* Remove fuzz and deadzone from the second joystick axis */ 135 + if (hdev->vendor == USB_VENDOR_ID_FFBEAST && 136 + hdev->product == USB_DEVICE_ID_FFBEAST_JOYSTICK) 137 + input_set_abs_params(input, ABS_Y, 138 + input->absinfo[ABS_Y].minimum, 139 + input->absinfo[ABS_Y].maximum, 0, 0); 140 + 141 + return 0; 142 + } 143 + 144 + static const struct hid_device_id universal_pidff_devices[] = { 145 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3), 146 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 147 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2), 148 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 149 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5), 150 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 151 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2), 152 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 153 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9), 154 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 155 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2), 156 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 157 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12), 158 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 159 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2), 160 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 161 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21), 162 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 163 + { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2), 164 + .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION }, 165 + { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) }, 166 + { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) }, 167 + { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP), 168 + .driver_data = HID_PIDFF_QUIRK_PERMISSIVE_CONTROL }, 169 + { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_JOYSTICK), }, 170 + { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_RUDDER), }, 171 + { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_WHEEL) }, 172 + { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10), 173 + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, 174 + { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12), 175 + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, 176 + { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE), 177 + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, 178 + { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2), 179 + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, 180 + { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF), 181 + .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY }, 182 + { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_INVICTA) }, 183 + { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) }, 184 + { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_LA_PRIMA) }, 185 + { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_TONY_KANAAN) }, 186 + { } 187 + }; 188 + MODULE_DEVICE_TABLE(hid, universal_pidff_devices); 189 + 190 + static struct hid_driver universal_pidff = { 191 + .name = "hid-universal-pidff", 192 + .id_table = universal_pidff_devices, 193 + .input_mapping = universal_pidff_input_mapping, 194 + .probe = universal_pidff_probe, 195 + .input_configured = universal_pidff_input_configured 196 + }; 197 + module_hid_driver(universal_pidff); 198 + 199 + MODULE_DESCRIPTION("Universal driver for USB PID Force Feedback devices"); 200 + MODULE_LICENSE("GPL"); 201 + MODULE_AUTHOR("Oleg Makarenko <oleg@makarenk.ooo>"); 202 + MODULE_AUTHOR("Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>");
+5 -9
drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
··· 557 557 558 558 pci_set_master(pdev); 559 559 560 - ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); 560 + mem_addr = pcim_iomap_region(pdev, 0, KBUILD_MODNAME); 561 + ret = PTR_ERR_OR_ZERO(mem_addr); 561 562 if (ret) { 562 563 dev_err_once(&pdev->dev, "Failed to get PCI regions, ret = %d.\n", ret); 563 564 goto disable_pci_device; 564 565 } 565 - 566 - mem_addr = pcim_iomap_table(pdev)[0]; 567 566 568 567 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 569 568 if (ret) { 570 569 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 571 570 if (ret) { 572 571 dev_err_once(&pdev->dev, "No usable DMA configuration %d\n", ret); 573 - goto unmap_io_region; 572 + goto disable_pci_device; 574 573 } 575 574 } 576 575 ··· 577 578 if (ret < 0) { 578 579 dev_err_once(&pdev->dev, 579 580 "Failed to allocate IRQ vectors. ret = %d\n", ret); 580 - goto unmap_io_region; 581 + goto disable_pci_device; 581 582 } 582 583 583 584 pdev->irq = pci_irq_vector(pdev, 0); ··· 586 587 if (IS_ERR(qcdev)) { 587 588 dev_err_once(&pdev->dev, "QuickI2C device init failed\n"); 588 589 ret = PTR_ERR(qcdev); 589 - goto unmap_io_region; 590 + goto disable_pci_device; 590 591 } 591 592 592 593 pci_set_drvdata(pdev, qcdev); ··· 665 666 quicki2c_dma_deinit(qcdev); 666 667 dev_deinit: 667 668 quicki2c_dev_deinit(qcdev); 668 - unmap_io_region: 669 - pcim_iounmap_regions(pdev, BIT(0)); 670 669 disable_pci_device: 671 670 pci_clear_master(pdev); 672 671 ··· 694 697 695 698 quicki2c_dev_deinit(qcdev); 696 699 697 - pcim_iounmap_regions(pdev, BIT(0)); 698 700 pci_clear_master(pdev); 699 701 } 700 702
+6 -10
drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
··· 426 426 427 427 thc_interrupt_enable(qsdev->thc_hw, true); 428 428 429 - qsdev->state = QUICKSPI_INITED; 429 + qsdev->state = QUICKSPI_INITIATED; 430 430 431 431 return qsdev; 432 432 } ··· 575 575 576 576 pci_set_master(pdev); 577 577 578 - ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); 578 + mem_addr = pcim_iomap_region(pdev, 0, KBUILD_MODNAME); 579 + ret = PTR_ERR_OR_ZERO(mem_addr); 579 580 if (ret) { 580 581 dev_err(&pdev->dev, "Failed to get PCI regions, ret = %d.\n", ret); 581 582 goto disable_pci_device; 582 583 } 583 - 584 - mem_addr = pcim_iomap_table(pdev)[0]; 585 584 586 585 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 587 586 if (ret) { 588 587 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 589 588 if (ret) { 590 589 dev_err(&pdev->dev, "No usable DMA configuration %d\n", ret); 591 - goto unmap_io_region; 590 + goto disable_pci_device; 592 591 } 593 592 } 594 593 ··· 595 596 if (ret < 0) { 596 597 dev_err(&pdev->dev, 597 598 "Failed to allocate IRQ vectors. ret = %d\n", ret); 598 - goto unmap_io_region; 599 + goto disable_pci_device; 599 600 } 600 601 601 602 pdev->irq = pci_irq_vector(pdev, 0); ··· 604 605 if (IS_ERR(qsdev)) { 605 606 dev_err(&pdev->dev, "QuickSPI device init failed\n"); 606 607 ret = PTR_ERR(qsdev); 607 - goto unmap_io_region; 608 + goto disable_pci_device; 608 609 } 609 610 610 611 pci_set_drvdata(pdev, qsdev); ··· 667 668 quickspi_dma_deinit(qsdev); 668 669 dev_deinit: 669 670 quickspi_dev_deinit(qsdev); 670 - unmap_io_region: 671 - pcim_iounmap_regions(pdev, BIT(0)); 672 671 disable_pci_device: 673 672 pci_clear_master(pdev); 674 673 ··· 696 699 697 700 quickspi_dev_deinit(qsdev); 698 701 699 - pcim_iounmap_regions(pdev, BIT(0)); 700 702 pci_clear_master(pdev); 701 703 } 702 704
+2 -2
drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
··· 57 57 58 58 enum quickspi_dev_state { 59 59 QUICKSPI_NONE, 60 + QUICKSPI_INITIATED, 60 61 QUICKSPI_RESETING, 61 - QUICKSPI_RESETED, 62 - QUICKSPI_INITED, 62 + QUICKSPI_RESET, 63 63 QUICKSPI_ENABLED, 64 64 QUICKSPI_DISABLED, 65 65 };
+1 -1
drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c
··· 333 333 return -EINVAL; 334 334 } 335 335 336 - qsdev->state = QUICKSPI_RESETED; 336 + qsdev->state = QUICKSPI_RESET; 337 337 338 338 ret = quickspi_get_device_descriptor(qsdev); 339 339 if (ret)
+1 -1
drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
··· 295 295 return; 296 296 297 297 for (i = 0; i < config->prd_tbl_num; i++) { 298 - if (!config->sgls[i] | !config->sgls_nent[i]) 298 + if (!config->sgls[i] || !config->sgls_nent[i]) 299 299 continue; 300 300 301 301 dma_unmap_sg(dev->dev, config->sgls[i],
+1
drivers/hid/usbhid/hid-core.c
··· 35 35 #include <linux/hid-debug.h> 36 36 #include <linux/hidraw.h> 37 37 #include "usbhid.h" 38 + #include "hid-pidff.h" 38 39 39 40 /* 40 41 * Version Information
+373 -198
drivers/hid/usbhid/hid-pidff.c
··· 3 3 * Force feedback driver for USB HID PID compliant devices 4 4 * 5 5 * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> 6 + * Upgraded 2025 by Oleg Makarenko and Tomasz Pakuła 6 7 */ 7 - 8 - /* 9 - */ 10 - 11 - /* #define DEBUG */ 12 8 13 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 10 11 + #include "hid-pidff.h" 15 12 #include <linux/input.h> 16 13 #include <linux/slab.h> 17 14 #include <linux/usb.h> 18 - 19 15 #include <linux/hid.h> 16 + #include <linux/minmax.h> 20 17 21 - #include "usbhid.h" 22 18 23 19 #define PID_EFFECTS_MAX 64 20 + #define PID_INFINITE U16_MAX 21 + 22 + /* Linux Force Feedback API uses miliseconds as time unit */ 23 + #define FF_TIME_EXPONENT -3 24 + #define FF_INFINITE 0 24 25 25 26 /* Report usage table used to put reports into an array */ 26 - 27 27 #define PID_SET_EFFECT 0 28 28 #define PID_EFFECT_OPERATION 1 29 29 #define PID_DEVICE_GAIN 2 ··· 44 44 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab, 45 45 0x5a, 0x5f, 0x6e, 0x73, 0x74 46 46 }; 47 + /* 48 + * device_control is really 0x95, but 0x96 specified 49 + * as it is the usage of the only field in that report. 50 + */ 47 51 48 - /* device_control is really 0x95, but 0x96 specified as it is the usage of 49 - the only field in that report */ 52 + /* PID special fields */ 53 + #define PID_EFFECT_TYPE 0x25 54 + #define PID_DIRECTION 0x57 55 + #define PID_EFFECT_OPERATION_ARRAY 0x78 56 + #define PID_BLOCK_LOAD_STATUS 0x8b 57 + #define PID_DEVICE_CONTROL_ARRAY 0x96 50 58 51 59 /* Value usage tables used to put fields and values into arrays */ 52 - 53 60 #define PID_EFFECT_BLOCK_INDEX 0 54 61 55 62 #define PID_DURATION 1 ··· 114 107 static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; 115 108 116 109 /* Special field key tables used to put special field keys into arrays */ 117 - 118 110 #define PID_ENABLE_ACTUATORS 0 119 - #define PID_RESET 1 120 - static const u8 pidff_device_control[] = { 0x97, 0x9a }; 111 + #define PID_DISABLE_ACTUATORS 1 112 + #define PID_STOP_ALL_EFFECTS 2 113 + #define PID_RESET 3 114 + #define PID_PAUSE 4 115 + #define PID_CONTINUE 5 116 + static const u8 pidff_device_control[] = { 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c }; 121 117 122 118 #define PID_CONSTANT 0 123 119 #define PID_RAMP 1 ··· 140 130 141 131 #define PID_BLOCK_LOAD_SUCCESS 0 142 132 #define PID_BLOCK_LOAD_FULL 1 143 - static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; 133 + #define PID_BLOCK_LOAD_ERROR 2 134 + static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e}; 144 135 145 136 #define PID_EFFECT_START 0 146 137 #define PID_EFFECT_STOP 1 147 138 static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; 139 + 140 + /* Polar direction 90 degrees (East) */ 141 + #define PIDFF_FIXED_WHEEL_DIRECTION 0x4000 148 142 149 143 struct pidff_usage { 150 144 struct hid_field *field; ··· 173 159 struct pidff_usage effect_operation[sizeof(pidff_effect_operation)]; 174 160 struct pidff_usage block_free[sizeof(pidff_block_free)]; 175 161 176 - /* Special field is a field that is not composed of 177 - usage<->value pairs that pidff_usage values are */ 162 + /* 163 + * Special field is a field that is not composed of 164 + * usage<->value pairs that pidff_usage values are 165 + */ 178 166 179 167 /* Special field in create_new_effect */ 180 168 struct hid_field *create_new_effect_type; ··· 200 184 int operation_id[sizeof(pidff_effect_operation_status)]; 201 185 202 186 int pid_id[PID_EFFECTS_MAX]; 187 + 188 + u32 quirks; 189 + u8 effect_count; 203 190 }; 191 + 192 + /* 193 + * Clamp value for a given field 194 + */ 195 + static s32 pidff_clamp(s32 i, struct hid_field *field) 196 + { 197 + s32 clamped = clamp(i, field->logical_minimum, field->logical_maximum); 198 + pr_debug("clamped from %d to %d", i, clamped); 199 + return clamped; 200 + } 204 201 205 202 /* 206 203 * Scale an unsigned value with range 0..max for the given field ··· 221 192 static int pidff_rescale(int i, int max, struct hid_field *field) 222 193 { 223 194 return i * (field->logical_maximum - field->logical_minimum) / max + 224 - field->logical_minimum; 195 + field->logical_minimum; 225 196 } 226 197 227 198 /* 228 - * Scale a signed value in range -0x8000..0x7fff for the given field 199 + * Scale a signed value in range S16_MIN..S16_MAX for the given field 229 200 */ 230 201 static int pidff_rescale_signed(int i, struct hid_field *field) 231 202 { 232 - return i == 0 ? 0 : i > 233 - 0 ? i * field->logical_maximum / 0x7fff : i * 234 - field->logical_minimum / -0x8000; 203 + if (i > 0) return i * field->logical_maximum / S16_MAX; 204 + if (i < 0) return i * field->logical_minimum / S16_MIN; 205 + return 0; 206 + } 207 + 208 + /* 209 + * Scale time value from Linux default (ms) to field units 210 + */ 211 + static u32 pidff_rescale_time(u16 time, struct hid_field *field) 212 + { 213 + u32 scaled_time = time; 214 + int exponent = field->unit_exponent; 215 + pr_debug("time field exponent: %d\n", exponent); 216 + 217 + for (;exponent < FF_TIME_EXPONENT; exponent++) 218 + scaled_time *= 10; 219 + for (;exponent > FF_TIME_EXPONENT; exponent--) 220 + scaled_time /= 10; 221 + 222 + pr_debug("time calculated from %d to %d\n", time, scaled_time); 223 + return scaled_time; 235 224 } 236 225 237 226 static void pidff_set(struct pidff_usage *usage, u16 value) 238 227 { 239 - usage->value[0] = pidff_rescale(value, 0xffff, usage->field); 228 + usage->value[0] = pidff_rescale(value, U16_MAX, usage->field); 240 229 pr_debug("calculated from %d to %d\n", value, usage->value[0]); 241 230 } 242 231 ··· 265 218 else { 266 219 if (value < 0) 267 220 usage->value[0] = 268 - pidff_rescale(-value, 0x8000, usage->field); 221 + pidff_rescale(-value, -S16_MIN, usage->field); 269 222 else 270 223 usage->value[0] = 271 - pidff_rescale(value, 0x7fff, usage->field); 224 + pidff_rescale(value, S16_MAX, usage->field); 272 225 } 273 226 pr_debug("calculated from %d to %d\n", value, usage->value[0]); 227 + } 228 + 229 + static void pidff_set_time(struct pidff_usage *usage, u16 time) 230 + { 231 + u32 modified_time = pidff_rescale_time(time, usage->field); 232 + usage->value[0] = pidff_clamp(modified_time, usage->field); 233 + } 234 + 235 + static void pidff_set_duration(struct pidff_usage *usage, u16 duration) 236 + { 237 + /* Infinite value conversion from Linux API -> PID */ 238 + if (duration == FF_INFINITE) 239 + duration = PID_INFINITE; 240 + 241 + /* PID defines INFINITE as the max possible value for duration field */ 242 + if (duration == PID_INFINITE) { 243 + usage->value[0] = (1U << usage->field->report_size) - 1; 244 + return; 245 + } 246 + 247 + pidff_set_time(usage, duration); 274 248 } 275 249 276 250 /* ··· 301 233 struct ff_envelope *envelope) 302 234 { 303 235 pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] = 304 - pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 236 + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 305 237 306 238 pidff->set_envelope[PID_ATTACK_LEVEL].value[0] = 307 - pidff_rescale(envelope->attack_level > 308 - 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff, 309 - pidff->set_envelope[PID_ATTACK_LEVEL].field); 239 + pidff_rescale(envelope->attack_level > 240 + S16_MAX ? S16_MAX : envelope->attack_level, S16_MAX, 241 + pidff->set_envelope[PID_ATTACK_LEVEL].field); 310 242 pidff->set_envelope[PID_FADE_LEVEL].value[0] = 311 - pidff_rescale(envelope->fade_level > 312 - 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff, 313 - pidff->set_envelope[PID_FADE_LEVEL].field); 243 + pidff_rescale(envelope->fade_level > 244 + S16_MAX ? S16_MAX : envelope->fade_level, S16_MAX, 245 + pidff->set_envelope[PID_FADE_LEVEL].field); 314 246 315 - pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length; 316 - pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; 247 + pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME], 248 + envelope->attack_length); 249 + pidff_set_time(&pidff->set_envelope[PID_FADE_TIME], 250 + envelope->fade_length); 317 251 318 252 hid_dbg(pidff->hid, "attack %u => %d\n", 319 253 envelope->attack_level, ··· 331 261 static int pidff_needs_set_envelope(struct ff_envelope *envelope, 332 262 struct ff_envelope *old) 333 263 { 334 - return envelope->attack_level != old->attack_level || 335 - envelope->fade_level != old->fade_level || 264 + bool needs_new_envelope; 265 + needs_new_envelope = envelope->attack_level != 0 || 266 + envelope->fade_level != 0 || 267 + envelope->attack_length != 0 || 268 + envelope->fade_length != 0; 269 + 270 + if (!needs_new_envelope) 271 + return false; 272 + 273 + if (!old) 274 + return needs_new_envelope; 275 + 276 + return envelope->attack_level != old->attack_level || 277 + envelope->fade_level != old->fade_level || 336 278 envelope->attack_length != old->attack_length || 337 - envelope->fade_length != old->fade_length; 279 + envelope->fade_length != old->fade_length; 338 280 } 339 281 340 282 /* ··· 383 301 pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 384 302 pidff->set_effect_type->value[0] = 385 303 pidff->create_new_effect_type->value[0]; 386 - pidff->set_effect[PID_DURATION].value[0] = effect->replay.length; 304 + 305 + pidff_set_duration(&pidff->set_effect[PID_DURATION], 306 + effect->replay.length); 307 + 387 308 pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; 388 - pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 389 - effect->trigger.interval; 309 + pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT], 310 + effect->trigger.interval); 390 311 pidff->set_effect[PID_GAIN].value[0] = 391 312 pidff->set_effect[PID_GAIN].field->logical_maximum; 392 313 pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; 393 - pidff->effect_direction->value[0] = 394 - pidff_rescale(effect->direction, 0xffff, 395 - pidff->effect_direction); 396 - pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; 314 + 315 + /* Use fixed direction if needed */ 316 + pidff->effect_direction->value[0] = pidff_rescale( 317 + pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ? 318 + PIDFF_FIXED_WHEEL_DIRECTION : effect->direction, 319 + U16_MAX, pidff->effect_direction); 320 + 321 + /* Omit setting delay field if it's missing */ 322 + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) 323 + pidff_set_time(&pidff->set_effect[PID_START_DELAY], 324 + effect->replay.delay); 397 325 398 326 hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], 399 327 HID_REQ_SET_REPORT); ··· 435 343 pidff_set_signed(&pidff->set_periodic[PID_OFFSET], 436 344 effect->u.periodic.offset); 437 345 pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); 438 - pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; 346 + pidff_set_time(&pidff->set_periodic[PID_PERIOD], 347 + effect->u.periodic.period); 439 348 440 349 hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC], 441 350 HID_REQ_SET_REPORT); 442 - 443 351 } 444 352 445 353 /* ··· 460 368 static void pidff_set_condition_report(struct pidff_device *pidff, 461 369 struct ff_effect *effect) 462 370 { 463 - int i; 371 + int i, max_axis; 372 + 373 + /* Devices missing Parameter Block Offset can only have one axis */ 374 + max_axis = pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO ? 1 : 2; 464 375 465 376 pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] = 466 377 pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 467 378 468 - for (i = 0; i < 2; i++) { 469 - pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; 379 + for (i = 0; i < max_axis; i++) { 380 + /* Omit Parameter Block Offset if missing */ 381 + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO)) 382 + pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; 383 + 470 384 pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET], 471 385 effect->u.condition[i].center); 472 386 pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], ··· 540 442 } 541 443 542 444 /* 445 + * Set device gain 446 + */ 447 + static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) 448 + { 449 + if (!pidff->device_gain[PID_DEVICE_GAIN_FIELD].field) 450 + return; 451 + 452 + pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); 453 + hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN], 454 + HID_REQ_SET_REPORT); 455 + } 456 + 457 + /* 458 + * Send device control report to the device 459 + */ 460 + static void pidff_set_device_control(struct pidff_device *pidff, int field) 461 + { 462 + int i, index; 463 + int field_index = pidff->control_id[field]; 464 + 465 + if (field_index < 1) 466 + return; 467 + 468 + /* Detect if the field is a bitmask variable or an array */ 469 + if (pidff->device_control->flags & HID_MAIN_ITEM_VARIABLE) { 470 + hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n"); 471 + 472 + /* Clear current bitmask */ 473 + for(i = 0; i < sizeof(pidff_device_control); i++) { 474 + index = pidff->control_id[i]; 475 + if (index < 1) 476 + continue; 477 + 478 + pidff->device_control->value[index - 1] = 0; 479 + } 480 + 481 + pidff->device_control->value[field_index - 1] = 1; 482 + } else { 483 + hid_dbg(pidff->hid, "DEVICE_CONTROL is an array\n"); 484 + pidff->device_control->value[0] = field_index; 485 + } 486 + 487 + hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); 488 + hid_hw_wait(pidff->hid); 489 + } 490 + 491 + /* 492 + * Modify actuators state 493 + */ 494 + static void pidff_set_actuators(struct pidff_device *pidff, bool enable) 495 + { 496 + hid_dbg(pidff->hid, "%s actuators\n", enable ? "Enable" : "Disable"); 497 + pidff_set_device_control(pidff, 498 + enable ? PID_ENABLE_ACTUATORS : PID_DISABLE_ACTUATORS); 499 + } 500 + 501 + /* 502 + * Reset the device, stop all effects, enable actuators 503 + */ 504 + static void pidff_reset(struct pidff_device *pidff) 505 + { 506 + /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ 507 + pidff_set_device_control(pidff, PID_RESET); 508 + pidff_set_device_control(pidff, PID_RESET); 509 + pidff->effect_count = 0; 510 + 511 + pidff_set_device_control(pidff, PID_STOP_ALL_EFFECTS); 512 + pidff_set_actuators(pidff, 1); 513 + } 514 + 515 + /* 516 + * Fetch pool report 517 + */ 518 + static void pidff_fetch_pool(struct pidff_device *pidff) 519 + { 520 + int i; 521 + struct hid_device *hid = pidff->hid; 522 + 523 + /* Repeat if PID_SIMULTANEOUS_MAX < 2 to make sure it's correct */ 524 + for(i = 0; i < 20; i++) { 525 + hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); 526 + hid_hw_wait(hid); 527 + 528 + if (!pidff->pool[PID_SIMULTANEOUS_MAX].value) 529 + return; 530 + if (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] >= 2) 531 + return; 532 + } 533 + hid_warn(hid, "device reports %d simultaneous effects\n", 534 + pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); 535 + } 536 + 537 + /* 543 538 * Send a request for effect upload to the device 539 + * 540 + * Reset and enable actuators if no effects were present on the device 544 541 * 545 542 * Returns 0 if device reported success, -ENOSPC if the device reported memory 546 543 * is full. Upon unknown response the function will retry for 60 times, if ··· 644 451 static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) 645 452 { 646 453 int j; 454 + 455 + if (!pidff->effect_count) 456 + pidff_reset(pidff); 647 457 648 458 pidff->create_new_effect_type->value[0] = efnum; 649 459 hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], ··· 667 471 hid_dbg(pidff->hid, "device reported free memory: %d bytes\n", 668 472 pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? 669 473 pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); 474 + 475 + pidff->effect_count++; 670 476 return 0; 671 477 } 672 478 if (pidff->block_load_status->value[0] == ··· 677 479 pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? 678 480 pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); 679 481 return -ENOSPC; 482 + } 483 + if (pidff->block_load_status->value[0] == 484 + pidff->status_id[PID_BLOCK_LOAD_ERROR]) { 485 + hid_dbg(pidff->hid, "device error during effect creation\n"); 486 + return -EREMOTEIO; 680 487 } 681 488 } 682 489 hid_err(pidff->hid, "pid_block_load failed 60 times\n"); ··· 701 498 } else { 702 499 pidff->effect_operation_status->value[0] = 703 500 pidff->operation_id[PID_EFFECT_START]; 704 - pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; 501 + pidff->effect_operation[PID_LOOP_COUNT].value[0] = 502 + pidff_clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field); 705 503 } 706 504 707 505 hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], ··· 715 511 static int pidff_playback(struct input_dev *dev, int effect_id, int value) 716 512 { 717 513 struct pidff_device *pidff = dev->ff->private; 718 - 719 514 pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); 720 - 721 515 return 0; 722 516 } 723 517 724 518 /* 725 519 * Erase effect with PID id 520 + * Decrease the device effect counter 726 521 */ 727 522 static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) 728 523 { 729 524 pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; 730 525 hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE], 731 526 HID_REQ_SET_REPORT); 527 + 528 + if (pidff->effect_count > 0) 529 + pidff->effect_count--; 732 530 } 733 531 734 532 /* ··· 743 537 744 538 hid_dbg(pidff->hid, "starting to erase %d/%d\n", 745 539 effect_id, pidff->pid_id[effect_id]); 746 - /* Wait for the queue to clear. We do not want a full fifo to 747 - prevent the effect removal. */ 540 + 541 + /* 542 + * Wait for the queue to clear. We do not want 543 + * a full fifo to prevent the effect removal. 544 + */ 748 545 hid_hw_wait(pidff->hid); 749 546 pidff_playback_pid(pidff, pid_id, 0); 750 547 pidff_erase_pid(pidff, pid_id); ··· 783 574 pidff_set_effect_report(pidff, effect); 784 575 if (!old || pidff_needs_set_constant(effect, old)) 785 576 pidff_set_constant_force_report(pidff, effect); 786 - if (!old || 787 - pidff_needs_set_envelope(&effect->u.constant.envelope, 788 - &old->u.constant.envelope)) 789 - pidff_set_envelope_report(pidff, 790 - &effect->u.constant.envelope); 577 + if (pidff_needs_set_envelope(&effect->u.constant.envelope, 578 + old ? &old->u.constant.envelope : NULL)) 579 + pidff_set_envelope_report(pidff, &effect->u.constant.envelope); 791 580 break; 792 581 793 582 case FF_PERIODIC: ··· 811 604 return -EINVAL; 812 605 } 813 606 607 + if (pidff->quirks & HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY) 608 + type_id = PID_SINE; 609 + 814 610 error = pidff_request_effect_upload(pidff, 815 611 pidff->type_id[type_id]); 816 612 if (error) ··· 823 613 pidff_set_effect_report(pidff, effect); 824 614 if (!old || pidff_needs_set_periodic(effect, old)) 825 615 pidff_set_periodic_report(pidff, effect); 826 - if (!old || 827 - pidff_needs_set_envelope(&effect->u.periodic.envelope, 828 - &old->u.periodic.envelope)) 829 - pidff_set_envelope_report(pidff, 830 - &effect->u.periodic.envelope); 616 + if (pidff_needs_set_envelope(&effect->u.periodic.envelope, 617 + old ? &old->u.periodic.envelope : NULL)) 618 + pidff_set_envelope_report(pidff, &effect->u.periodic.envelope); 831 619 break; 832 620 833 621 case FF_RAMP: ··· 839 631 pidff_set_effect_report(pidff, effect); 840 632 if (!old || pidff_needs_set_ramp(effect, old)) 841 633 pidff_set_ramp_force_report(pidff, effect); 842 - if (!old || 843 - pidff_needs_set_envelope(&effect->u.ramp.envelope, 844 - &old->u.ramp.envelope)) 845 - pidff_set_envelope_report(pidff, 846 - &effect->u.ramp.envelope); 634 + if (pidff_needs_set_envelope(&effect->u.ramp.envelope, 635 + old ? &old->u.ramp.envelope : NULL)) 636 + pidff_set_envelope_report(pidff, &effect->u.ramp.envelope); 847 637 break; 848 638 849 639 case FF_SPRING: 850 - if (!old) { 851 - error = pidff_request_effect_upload(pidff, 852 - pidff->type_id[PID_SPRING]); 853 - if (error) 854 - return error; 855 - } 856 - if (!old || pidff_needs_set_effect(effect, old)) 857 - pidff_set_effect_report(pidff, effect); 858 - if (!old || pidff_needs_set_condition(effect, old)) 859 - pidff_set_condition_report(pidff, effect); 860 - break; 861 - 640 + case FF_DAMPER: 641 + case FF_INERTIA: 862 642 case FF_FRICTION: 863 643 if (!old) { 644 + switch(effect->type) { 645 + case FF_SPRING: 646 + type_id = PID_SPRING; 647 + break; 648 + case FF_DAMPER: 649 + type_id = PID_DAMPER; 650 + break; 651 + case FF_INERTIA: 652 + type_id = PID_INERTIA; 653 + break; 654 + case FF_FRICTION: 655 + type_id = PID_FRICTION; 656 + break; 657 + } 864 658 error = pidff_request_effect_upload(pidff, 865 - pidff->type_id[PID_FRICTION]); 866 - if (error) 867 - return error; 868 - } 869 - if (!old || pidff_needs_set_effect(effect, old)) 870 - pidff_set_effect_report(pidff, effect); 871 - if (!old || pidff_needs_set_condition(effect, old)) 872 - pidff_set_condition_report(pidff, effect); 873 - break; 874 - 875 - case FF_DAMPER: 876 - if (!old) { 877 - error = pidff_request_effect_upload(pidff, 878 - pidff->type_id[PID_DAMPER]); 879 - if (error) 880 - return error; 881 - } 882 - if (!old || pidff_needs_set_effect(effect, old)) 883 - pidff_set_effect_report(pidff, effect); 884 - if (!old || pidff_needs_set_condition(effect, old)) 885 - pidff_set_condition_report(pidff, effect); 886 - break; 887 - 888 - case FF_INERTIA: 889 - if (!old) { 890 - error = pidff_request_effect_upload(pidff, 891 - pidff->type_id[PID_INERTIA]); 659 + pidff->type_id[type_id]); 892 660 if (error) 893 661 return error; 894 662 } ··· 893 709 */ 894 710 static void pidff_set_gain(struct input_dev *dev, u16 gain) 895 711 { 896 - struct pidff_device *pidff = dev->ff->private; 897 - 898 - pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); 899 - hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN], 900 - HID_REQ_SET_REPORT); 712 + pidff_set_gain_report(dev->ff->private, gain); 901 713 } 902 714 903 715 static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) ··· 916 736 pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; 917 737 pidff_set(&pidff->set_effect[PID_GAIN], magnitude); 918 738 pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; 919 - pidff->set_effect[PID_START_DELAY].value[0] = 0; 739 + 740 + /* Omit setting delay field if it's missing */ 741 + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) 742 + pidff->set_effect[PID_START_DELAY].value[0] = 0; 920 743 921 744 hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], 922 745 HID_REQ_SET_REPORT); ··· 930 747 */ 931 748 static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) 932 749 { 933 - struct pidff_device *pidff = dev->ff->private; 934 - 935 - pidff_autocenter(pidff, magnitude); 750 + pidff_autocenter(dev->ff->private, magnitude); 936 751 } 937 752 938 753 /* ··· 939 758 static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, 940 759 struct hid_report *report, int count, int strict) 941 760 { 761 + if (!report) { 762 + pr_debug("pidff_find_fields, null report\n"); 763 + return -1; 764 + } 765 + 942 766 int i, j, k, found; 767 + int return_value = 0; 943 768 944 769 for (k = 0; k < count; k++) { 945 770 found = 0; ··· 970 783 if (found) 971 784 break; 972 785 } 973 - if (!found && strict) { 786 + if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) { 787 + pr_debug("Delay field not found, but that's OK\n"); 788 + pr_debug("Setting MISSING_DELAY quirk\n"); 789 + return_value |= HID_PIDFF_QUIRK_MISSING_DELAY; 790 + } 791 + else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) { 792 + pr_debug("PBO field not found, but that's OK\n"); 793 + pr_debug("Setting MISSING_PBO quirk\n"); 794 + return_value |= HID_PIDFF_QUIRK_MISSING_PBO; 795 + } 796 + else if (!found && strict) { 974 797 pr_debug("failed to locate %d\n", k); 975 798 return -1; 976 799 } 977 800 } 978 - return 0; 801 + return return_value; 979 802 } 980 803 981 804 /* ··· 1068 871 static struct hid_field *pidff_find_special_field(struct hid_report *report, 1069 872 int usage, int enforce_min) 1070 873 { 874 + if (!report) { 875 + pr_debug("pidff_find_special_field, null report\n"); 876 + return NULL; 877 + } 878 + 1071 879 int i; 1072 880 1073 881 for (i = 0; i < report->maxfield; i++) { ··· 1125 923 1126 924 pidff->create_new_effect_type = 1127 925 pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT], 1128 - 0x25, 1); 926 + PID_EFFECT_TYPE, 1); 1129 927 pidff->set_effect_type = 1130 928 pidff_find_special_field(pidff->reports[PID_SET_EFFECT], 1131 - 0x25, 1); 929 + PID_EFFECT_TYPE, 1); 1132 930 pidff->effect_direction = 1133 931 pidff_find_special_field(pidff->reports[PID_SET_EFFECT], 1134 - 0x57, 0); 932 + PID_DIRECTION, 0); 1135 933 pidff->device_control = 1136 934 pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], 1137 - 0x96, 1); 935 + PID_DEVICE_CONTROL_ARRAY, 936 + !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); 937 + 1138 938 pidff->block_load_status = 1139 939 pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], 1140 - 0x8b, 1); 940 + PID_BLOCK_LOAD_STATUS, 1); 1141 941 pidff->effect_operation_status = 1142 942 pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION], 1143 - 0x78, 1); 943 + PID_EFFECT_OPERATION_ARRAY, 1); 1144 944 1145 945 hid_dbg(pidff->hid, "search done\n"); 1146 946 ··· 1170 966 hid_err(pidff->hid, "effect operation field not found\n"); 1171 967 return -1; 1172 968 } 1173 - 1174 - pidff_find_special_keys(pidff->control_id, pidff->device_control, 1175 - pidff_device_control, 1176 - sizeof(pidff_device_control)); 1177 969 1178 970 PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control); 1179 971 ··· 1249 1049 set_bit(FF_FRICTION, dev->ffbit); 1250 1050 1251 1051 return 0; 1252 - 1253 1052 } 1254 1053 1255 1054 #define PIDFF_FIND_FIELDS(name, report, strict) \ ··· 1261 1062 */ 1262 1063 static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) 1263 1064 { 1264 - int envelope_ok = 0; 1065 + int status = 0; 1265 1066 1266 - if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { 1067 + /* Save info about the device not having the DELAY ffb field. */ 1068 + status = PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1); 1069 + if (status == -1) { 1267 1070 hid_err(pidff->hid, "unknown set_effect report layout\n"); 1268 1071 return -ENODEV; 1269 1072 } 1073 + pidff->quirks |= status; 1074 + 1075 + if (status & HID_PIDFF_QUIRK_MISSING_DELAY) 1076 + hid_dbg(pidff->hid, "Adding MISSING_DELAY quirk\n"); 1077 + 1270 1078 1271 1079 PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); 1272 1080 if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { ··· 1291 1085 return -ENODEV; 1292 1086 } 1293 1087 1294 - if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) 1295 - envelope_ok = 1; 1296 - 1297 1088 if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev)) 1298 1089 return -ENODEV; 1299 1090 1300 - if (!envelope_ok) { 1091 + if (PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) { 1301 1092 if (test_and_clear_bit(FF_CONSTANT, dev->ffbit)) 1302 1093 hid_warn(pidff->hid, 1303 1094 "has constant effect but no envelope\n"); ··· 1319 1116 clear_bit(FF_RAMP, dev->ffbit); 1320 1117 } 1321 1118 1322 - if ((test_bit(FF_SPRING, dev->ffbit) || 1323 - test_bit(FF_DAMPER, dev->ffbit) || 1324 - test_bit(FF_FRICTION, dev->ffbit) || 1325 - test_bit(FF_INERTIA, dev->ffbit)) && 1326 - PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { 1327 - hid_warn(pidff->hid, "unknown condition effect layout\n"); 1328 - clear_bit(FF_SPRING, dev->ffbit); 1329 - clear_bit(FF_DAMPER, dev->ffbit); 1330 - clear_bit(FF_FRICTION, dev->ffbit); 1331 - clear_bit(FF_INERTIA, dev->ffbit); 1119 + if (test_bit(FF_SPRING, dev->ffbit) || 1120 + test_bit(FF_DAMPER, dev->ffbit) || 1121 + test_bit(FF_FRICTION, dev->ffbit) || 1122 + test_bit(FF_INERTIA, dev->ffbit)) { 1123 + status = PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1); 1124 + 1125 + if (status < 0) { 1126 + hid_warn(pidff->hid, "unknown condition effect layout\n"); 1127 + clear_bit(FF_SPRING, dev->ffbit); 1128 + clear_bit(FF_DAMPER, dev->ffbit); 1129 + clear_bit(FF_FRICTION, dev->ffbit); 1130 + clear_bit(FF_INERTIA, dev->ffbit); 1131 + } 1132 + pidff->quirks |= status; 1332 1133 } 1333 1134 1334 1135 if (test_bit(FF_PERIODIC, dev->ffbit) && ··· 1347 1140 set_bit(FF_GAIN, dev->ffbit); 1348 1141 1349 1142 return 0; 1350 - } 1351 - 1352 - /* 1353 - * Reset the device 1354 - */ 1355 - static void pidff_reset(struct pidff_device *pidff) 1356 - { 1357 - struct hid_device *hid = pidff->hid; 1358 - int i = 0; 1359 - 1360 - pidff->device_control->value[0] = pidff->control_id[PID_RESET]; 1361 - /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ 1362 - hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); 1363 - hid_hw_wait(hid); 1364 - hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); 1365 - hid_hw_wait(hid); 1366 - 1367 - pidff->device_control->value[0] = 1368 - pidff->control_id[PID_ENABLE_ACTUATORS]; 1369 - hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); 1370 - hid_hw_wait(hid); 1371 - 1372 - /* pool report is sometimes messed up, refetch it */ 1373 - hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); 1374 - hid_hw_wait(hid); 1375 - 1376 - if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { 1377 - while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { 1378 - if (i++ > 20) { 1379 - hid_warn(pidff->hid, 1380 - "device reports %d simultaneous effects\n", 1381 - pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); 1382 - break; 1383 - } 1384 - hid_dbg(pidff->hid, "pid_pool requested again\n"); 1385 - hid_hw_request(hid, pidff->reports[PID_POOL], 1386 - HID_REQ_GET_REPORT); 1387 - hid_hw_wait(hid); 1388 - } 1389 - } 1390 1143 } 1391 1144 1392 1145 /* ··· 1373 1206 1374 1207 if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] == 1375 1208 pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) { 1376 - pidff_autocenter(pidff, 0xffff); 1209 + pidff_autocenter(pidff, U16_MAX); 1377 1210 set_bit(FF_AUTOCENTER, dev->ffbit); 1378 1211 } else { 1379 1212 hid_notice(pidff->hid, 1380 1213 "device has unknown autocenter control method\n"); 1381 1214 } 1382 - 1383 1215 pidff_erase_pid(pidff, 1384 1216 pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]); 1385 1217 1386 1218 return 0; 1387 - 1388 1219 } 1389 1220 1390 1221 /* 1391 1222 * Check if the device is PID and initialize it 1223 + * Set initial quirks 1392 1224 */ 1393 - int hid_pidff_init(struct hid_device *hid) 1225 + int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) 1394 1226 { 1395 1227 struct pidff_device *pidff; 1396 1228 struct hid_input *hidinput = list_entry(hid->inputs.next, ··· 1411 1245 return -ENOMEM; 1412 1246 1413 1247 pidff->hid = hid; 1248 + pidff->quirks = initial_quirks; 1249 + pidff->effect_count = 0; 1414 1250 1415 1251 hid_device_io_start(hid); 1416 1252 ··· 1429 1261 if (error) 1430 1262 goto fail; 1431 1263 1432 - pidff_reset(pidff); 1433 - 1434 - if (test_bit(FF_GAIN, dev->ffbit)) { 1435 - pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); 1436 - hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN], 1437 - HID_REQ_SET_REPORT); 1438 - } 1439 - 1264 + /* pool report is sometimes messed up, refetch it */ 1265 + pidff_fetch_pool(pidff); 1266 + pidff_set_gain_report(pidff, U16_MAX); 1440 1267 error = pidff_check_autocenter(pidff, dev); 1441 1268 if (error) 1442 1269 goto fail; ··· 1474 1311 ff->playback = pidff_playback; 1475 1312 1476 1313 hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); 1314 + hid_dbg(dev, "Active quirks mask: 0x%x\n", pidff->quirks); 1477 1315 1478 1316 hid_device_io_stop(hid); 1479 1317 ··· 1485 1321 1486 1322 kfree(pidff); 1487 1323 return error; 1324 + } 1325 + EXPORT_SYMBOL_GPL(hid_pidff_init_with_quirks); 1326 + 1327 + /* 1328 + * Check if the device is PID and initialize it 1329 + * Wrapper made to keep the compatibility with old 1330 + * init function 1331 + */ 1332 + int hid_pidff_init(struct hid_device *hid) 1333 + { 1334 + return hid_pidff_init_with_quirks(hid, 0); 1488 1335 }
+33
drivers/hid/usbhid/hid-pidff.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + #ifndef __HID_PIDFF_H 3 + #define __HID_PIDFF_H 4 + 5 + #include <linux/hid.h> 6 + 7 + /* HID PIDFF quirks */ 8 + 9 + /* Delay field (0xA7) missing. Skip it during set effect report upload */ 10 + #define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0) 11 + 12 + /* Missing Paramter block offset (0x23). Skip it during SET_CONDITION 13 + report upload */ 14 + #define HID_PIDFF_QUIRK_MISSING_PBO BIT(1) 15 + 16 + /* Initialise device control field even if logical_minimum != 1 */ 17 + #define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2) 18 + 19 + /* Use fixed 0x4000 direction during SET_EFFECT report upload */ 20 + #define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3) 21 + 22 + /* Force all periodic effects to be uploaded as SINE */ 23 + #define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) 24 + 25 + #ifdef CONFIG_HID_PID 26 + int hid_pidff_init(struct hid_device *hid); 27 + int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks); 28 + #else 29 + #define hid_pidff_init NULL 30 + #define hid_pidff_init_with_quirks NULL 31 + #endif 32 + 33 + #endif
+1 -1
drivers/hid/usbhid/usbkbd.c
··· 160 160 return -1; 161 161 162 162 spin_lock_irqsave(&kbd->leds_lock, flags); 163 - kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | 163 + kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 4) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | 164 164 (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | 165 165 (!!test_bit(LED_NUML, dev->led)); 166 166
+21 -14
drivers/hid/wacom_sys.c
··· 69 69 struct kfifo_rec_ptr_2 *fifo) 70 70 { 71 71 while (!kfifo_is_empty(fifo)) { 72 - u8 buf[WACOM_PKGLEN_MAX]; 73 - int size; 72 + int size = kfifo_peek_len(fifo); 73 + u8 *buf = kzalloc(size, GFP_KERNEL); 74 + unsigned int count; 74 75 int err; 75 76 76 - size = kfifo_out(fifo, buf, sizeof(buf)); 77 + count = kfifo_out(fifo, buf, size); 78 + if (count != size) { 79 + // Hard to say what is the "right" action in this 80 + // circumstance. Skipping the entry and continuing 81 + // to flush seems reasonable enough, however. 82 + hid_warn(hdev, "%s: removed fifo entry with unexpected size\n", 83 + __func__); 84 + continue; 85 + } 77 86 err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false); 78 87 if (err) { 79 88 hid_warn(hdev, "%s: unable to flush event due to error %d\n", 80 89 __func__, err); 81 90 } 91 + 92 + kfree(buf); 82 93 } 83 94 } 84 95 ··· 169 158 if (wacom->wacom_wac.features.type == BOOTLOADER) 170 159 return 0; 171 160 172 - if (size > WACOM_PKGLEN_MAX) 173 - return 1; 174 - 175 161 if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size)) 176 162 return -1; 177 163 178 - memcpy(wacom->wacom_wac.data, raw_data, size); 164 + wacom->wacom_wac.data = raw_data; 179 165 180 166 wacom_wac_irq(&wacom->wacom_wac, size); 181 167 ··· 1294 1286 static int wacom_devm_kfifo_alloc(struct wacom *wacom) 1295 1287 { 1296 1288 struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1289 + int fifo_size = min(PAGE_SIZE, 10 * wacom_wac->features.pktlen); 1297 1290 struct kfifo_rec_ptr_2 *pen_fifo; 1298 1291 int error; 1299 1292 ··· 1305 1296 if (!pen_fifo) 1306 1297 return -ENOMEM; 1307 1298 1308 - error = kfifo_alloc(pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL); 1299 + error = kfifo_alloc(pen_fifo, fifo_size, GFP_KERNEL); 1309 1300 if (error) { 1310 1301 devres_free(pen_fifo); 1311 1302 return error; ··· 2361 2352 unsigned int connect_mask = HID_CONNECT_HIDRAW; 2362 2353 2363 2354 features->pktlen = wacom_compute_pktlen(hdev); 2364 - if (features->pktlen > WACOM_PKGLEN_MAX) 2365 - return -EINVAL; 2366 2355 2367 2356 if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL)) 2368 2357 return -ENOMEM; 2358 + 2359 + error = wacom_devm_kfifo_alloc(wacom); 2360 + if (error) 2361 + goto fail; 2369 2362 2370 2363 wacom->resources = true; 2371 2364 ··· 2831 2820 2832 2821 if (features->check_for_hid_type && features->hid_type != hdev->type) 2833 2822 return -ENODEV; 2834 - 2835 - error = wacom_devm_kfifo_alloc(wacom); 2836 - if (error) 2837 - return error; 2838 2823 2839 2824 wacom_wac->hid_data.inputmode = -1; 2840 2825 wacom_wac->mode_report = -1;
+4 -4
drivers/hid/wacom_wac.c
··· 1201 1201 1202 1202 static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) 1203 1203 { 1204 - unsigned char data[WACOM_PKGLEN_MAX]; 1204 + u8 *data = kmemdup(wacom->data, len, GFP_KERNEL); 1205 1205 int i = 1; 1206 1206 unsigned power_raw, battery_capacity, bat_charging, ps_connected; 1207 - 1208 - memcpy(data, wacom->data, len); 1209 1207 1210 1208 switch (data[0]) { 1211 1209 case 0x04: ··· 1228 1230 dev_dbg(wacom->pen_input->dev.parent, 1229 1231 "Unknown report: %d,%d size:%zu\n", 1230 1232 data[0], data[1], len); 1231 - return 0; 1233 + break; 1232 1234 } 1235 + 1236 + kfree(data); 1233 1237 return 0; 1234 1238 } 1235 1239
+2 -5
drivers/hid/wacom_wac.h
··· 7 7 #include <linux/hid.h> 8 8 #include <linux/kfifo.h> 9 9 10 - /* maximum packet length for USB/BT devices */ 11 - #define WACOM_PKGLEN_MAX 361 12 - 13 10 #define WACOM_NAME_MAX 64 14 11 #define WACOM_MAX_REMOTES 5 15 12 #define WACOM_STATUS_UNKNOWN 255 ··· 274 277 unsigned touch_max; 275 278 int oVid; 276 279 int oPid; 277 - int pktlen; 280 + unsigned int pktlen; 278 281 bool check_for_hid_type; 279 282 int hid_type; 280 283 }; ··· 338 341 char pen_name[WACOM_NAME_MAX]; 339 342 char touch_name[WACOM_NAME_MAX]; 340 343 char pad_name[WACOM_NAME_MAX]; 341 - unsigned char data[WACOM_PKGLEN_MAX]; 344 + u8 *data; 342 345 int tool[2]; 343 346 int id[2]; 344 347 __u64 serial[2];
+2 -6
include/linux/hid.h
··· 81 81 #define HID_MAIN_ITEM_TAG_FEATURE 11 82 82 #define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 83 83 #define HID_MAIN_ITEM_TAG_END_COLLECTION 12 84 + #define HID_MAIN_ITEM_TAG_RESERVED_MIN 13 85 + #define HID_MAIN_ITEM_TAG_RESERVED_MAX 15 84 86 85 87 /* 86 88 * HID report descriptor main item contents ··· 1223 1221 unsigned long hid_lookup_quirk(const struct hid_device *hdev); 1224 1222 int hid_quirks_init(char **quirks_param, __u16 bus, int count); 1225 1223 void hid_quirks_exit(__u16 bus); 1226 - 1227 - #ifdef CONFIG_HID_PID 1228 - int hid_pidff_init(struct hid_device *hid); 1229 - #else 1230 - #define hid_pidff_init NULL 1231 - #endif 1232 1224 1233 1225 #define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__) 1234 1226
+51
sound/usb/mixer_quirks.c
··· 4227 4227 } 4228 4228 } 4229 4229 4230 + /* 4231 + * Some Plantronics headsets have control names that don't meet ALSA naming 4232 + * standards. This function fixes nonstandard source names. By the time 4233 + * this function is called the control name should look like one of these: 4234 + * "source names Playback Volume" 4235 + * "source names Playback Switch" 4236 + * "source names Capture Volume" 4237 + * "source names Capture Switch" 4238 + * If any of the trigger words are found in the name then the name will 4239 + * be changed to: 4240 + * "Headset Playback Volume" 4241 + * "Headset Playback Switch" 4242 + * "Headset Capture Volume" 4243 + * "Headset Capture Switch" 4244 + * depending on the current suffix. 4245 + */ 4246 + static void snd_fix_plt_name(struct snd_usb_audio *chip, 4247 + struct snd_ctl_elem_id *id) 4248 + { 4249 + /* no variant of "Sidetone" should be added to this list */ 4250 + static const char * const trigger[] = { 4251 + "Earphone", "Microphone", "Receive", "Transmit" 4252 + }; 4253 + static const char * const suffix[] = { 4254 + " Playback Volume", " Playback Switch", 4255 + " Capture Volume", " Capture Switch" 4256 + }; 4257 + int i; 4258 + 4259 + for (i = 0; i < ARRAY_SIZE(trigger); i++) 4260 + if (strstr(id->name, trigger[i])) 4261 + goto triggered; 4262 + usb_audio_dbg(chip, "no change in %s\n", id->name); 4263 + return; 4264 + 4265 + triggered: 4266 + for (i = 0; i < ARRAY_SIZE(suffix); i++) 4267 + if (strstr(id->name, suffix[i])) { 4268 + usb_audio_dbg(chip, "fixing kctl name %s\n", id->name); 4269 + snprintf(id->name, sizeof(id->name), "Headset%s", 4270 + suffix[i]); 4271 + return; 4272 + } 4273 + usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name); 4274 + } 4275 + 4230 4276 void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, 4231 4277 struct usb_mixer_elem_info *cval, int unitid, 4232 4278 struct snd_kcontrol *kctl) ··· 4290 4244 cval->min_mute = 1; 4291 4245 break; 4292 4246 } 4247 + 4248 + /* ALSA-ify some Plantronics headset control names */ 4249 + if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && 4250 + (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) 4251 + snd_fix_plt_name(mixer->chip, &kctl->id); 4293 4252 } 4294 4253