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

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

Pull HID updates from Jiri Kosina:

- improvement in the way hid-bpf coexists with specific drivers (others
than hid-generic) that are already bound to devices (Benjamin
Tissoires)

- removal of three way-too-aggressive BUG_ON()s from HID drivers (He
Lugang)

- assorted cleanups and small code fixes to HID core (Dmitry Torokhov,
Yan Zhen, Nathan Chancellor, Andy Shevchenko)

- support for Corsair Void headset family (Stuart Hayhurst)

- Support for Goodix GT7986U SPI (Charles Wang)

- initial vendor-specific driver for Kysona, currently adding support
for Kysona M600 (Lode Willems)

- other assorted code cleanups and small bugfixes all over the place

* tag 'hid-for-linus-2024111801' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (40 commits)
HID: multitouch: make mt_set_mode() less cryptic
HID: hid-goodix-spi: Add OF supports
dt-bindings: input: Goodix GT7986U SPI HID Touchscreen
HID: hyperv: streamline driver probe to avoid devres issues
HID: magicmouse: Apple Magic Trackpad 2 USB-C driver support
HID: rmi: Add select RMI4_F3A in Kconfig
HID: wacom: Interpret tilt data from Intuos Pro BT as signed values
HID: steelseries: Add capacity_level mapping
HID: steelseries: Fix battery requests stopping after some time
HID: hid-goodix: Fix HID get/set feature operation overwritten problem
HID: hid-goodix: Return 0 when receiving an empty HID feature package
HID: bpf: drop use of Logical|Physical|UsageRange
HID: bpf: Fix Rapoo M50 Plus Silent side buttons
HID: bpf: Fix NKRO on Mistel MD770
HID: replace BUG_ON() with WARN_ON()
HID: wacom: Set eraser status when either 'Eraser' or 'Invert' usage is set
HID: Kysona: add basic online status
HID: Kysona: check battery status every 5s using a workqueue
HID: Kysona: Add basic battery reporting for Kysona M600
HID: Add IDs for Kysona
...

+2287 -411
+38
Documentation/ABI/testing/sysfs-driver-hid-corsair-void
··· 1 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/fw_version_headset 2 + Date: January 2024 3 + KernelVersion: 6.13 4 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 5 + Description: (R) The firmware version of the headset 6 + * Returns -ENODATA if no version was reported 7 + 8 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/fw_version_receiver 9 + Date: January 2024 10 + KernelVersion: 6.13 11 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 12 + Description: (R) The firmware version of the receiver 13 + 14 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/microphone_up 15 + Date: July 2023 16 + KernelVersion: 6.13 17 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 18 + Description: (R) Get the physical position of the microphone 19 + * 1 -> Microphone up 20 + * 0 -> Microphone down 21 + 22 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/send_alert 23 + Date: July 2023 24 + KernelVersion: 6.13 25 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 26 + Description: (W) Play a built-in notification from the headset (0 / 1) 27 + 28 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/set_sidetone 29 + Date: December 2023 30 + KernelVersion: 6.13 31 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 32 + Description: (W) Set the sidetone volume (0 - sidetone_max) 33 + 34 + What: /sys/bus/hid/drivers/hid-corsair-void/<dev>/sidetone_max 35 + Date: July 2024 36 + KernelVersion: 6.13 37 + Contact: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> 38 + Description: (R) Report the maximum sidetone volume
+69
Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/input/goodix,gt7986u-spifw.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Goodix GT7986U SPI HID Touchscreen 8 + 9 + maintainers: 10 + - Charles Wang <charles.goodix@gmail.com> 11 + 12 + description: | 13 + Supports the Goodix GT7986U touchscreen. 14 + This touch controller reports data packaged according to the HID protocol 15 + over the SPI bus, but it is incompatible with Microsoft's HID-over-SPI protocol. 16 + 17 + NOTE: these bindings are distinct from the bindings used with the 18 + GT7986U when the chip is running I2C firmware. This is because there's 19 + not a single device that talks over both I2C and SPI but rather 20 + distinct touchscreens that happen to be built with the same ASIC but 21 + that are distinct products running distinct firmware. 22 + 23 + allOf: 24 + - $ref: /schemas/spi/spi-peripheral-props.yaml# 25 + 26 + properties: 27 + compatible: 28 + enum: 29 + - goodix,gt7986u-spifw 30 + 31 + reg: 32 + maxItems: 1 33 + 34 + interrupts: 35 + maxItems: 1 36 + 37 + reset-gpios: 38 + maxItems: 1 39 + 40 + spi-max-frequency: true 41 + 42 + required: 43 + - compatible 44 + - reg 45 + - interrupts 46 + - reset-gpios 47 + 48 + unevaluatedProperties: false 49 + 50 + examples: 51 + - | 52 + #include <dt-bindings/interrupt-controller/irq.h> 53 + #include <dt-bindings/gpio/gpio.h> 54 + 55 + spi { 56 + #address-cells = <1>; 57 + #size-cells = <0>; 58 + 59 + touchscreen@0 { 60 + compatible = "goodix,gt7986u-spifw"; 61 + reg = <0>; 62 + interrupt-parent = <&gpio>; 63 + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; 64 + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; 65 + spi-max-frequency = <10000000>; 66 + }; 67 + }; 68 + 69 + ...
+13
drivers/hid/Kconfig
··· 213 213 config HID_CORSAIR 214 214 tristate "Corsair devices" 215 215 depends on USB_HID && LEDS_CLASS 216 + select POWER_SUPPLY 216 217 help 217 218 Support for Corsair devices that are not fully compliant with the 218 219 HID standard. 220 + Support for Corsair Void headsets. 219 221 220 222 Supported devices: 221 223 - Vengeance K90 222 224 - Scimitar PRO RGB 225 + - Corsair Void headsets 223 226 224 227 config HID_COUGAR 225 228 tristate "Cougar devices" ··· 467 464 - EasyPen i405X tablet 468 465 - MousePen i608X tablet 469 466 - EasyPen M610X tablet 467 + 468 + config HID_KYSONA 469 + tristate "Kysona devices" 470 + depends on USB_HID 471 + help 472 + Support for Kysona mice. 473 + 474 + Say Y here if you have a Kysona M600 mouse 475 + and want to be able to read its battery capacity. 470 476 471 477 config HID_UCLOGIC 472 478 tristate "UC-Logic" ··· 1108 1096 select RMI4_F11 1109 1097 select RMI4_F12 1110 1098 select RMI4_F30 1099 + select RMI4_F3A 1111 1100 help 1112 1101 Support for Synaptics RMI4 touchpads. 1113 1102 Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid
+2 -1
drivers/hid/Makefile
··· 38 38 obj-$(CONFIG_HID_CHERRY) += hid-cherry.o 39 39 obj-$(CONFIG_HID_CHICONY) += hid-chicony.o 40 40 obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o 41 - obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o 41 + obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o hid-corsair-void.o 42 42 obj-$(CONFIG_HID_COUGAR) += hid-cougar.o 43 43 obj-$(CONFIG_HID_CP2112) += hid-cp2112.o 44 44 obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o ··· 70 70 obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o 71 71 obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o 72 72 obj-$(CONFIG_HID_KYE) += hid-kye.o 73 + obj-$(CONFIG_HID_KYSONA) += hid-kysona.o 73 74 obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o 74 75 obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o 75 76 obj-$(CONFIG_HID_LETSKETCH) += hid-letsketch.o
+6 -3
drivers/hid/bpf/hid_bpf_dispatch.c
··· 148 148 } 149 149 EXPORT_SYMBOL_GPL(dispatch_hid_bpf_output_report); 150 150 151 - u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size) 151 + const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size) 152 152 { 153 153 int ret; 154 154 struct hid_bpf_ctx_kern ctx_kern = { ··· 183 183 184 184 ignore_bpf: 185 185 kfree(ctx_kern.data); 186 - return kmemdup(rdesc, *size, GFP_KERNEL); 186 + return rdesc; 187 187 } 188 188 EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); 189 189 ··· 260 260 261 261 int hid_bpf_reconnect(struct hid_device *hdev) 262 262 { 263 - if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) 263 + if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) { 264 + /* trigger call to call_hid_bpf_rdesc_fixup() during the next probe */ 265 + hdev->bpf_rsize = 0; 264 266 return device_reprobe(&hdev->dev); 267 + } 265 268 266 269 return 0; 267 270 }
+1
drivers/hid/bpf/hid_bpf_struct_ops.c
··· 79 79 WRITE_RANGE(hid_device, name, true), 80 80 WRITE_RANGE(hid_device, uniq, true), 81 81 WRITE_RANGE(hid_device, phys, true), 82 + WRITE_RANGE(hid_device, quirks, false), 82 83 }; 83 84 #undef WRITE_RANGE 84 85 const struct btf_type *state = NULL;
+44 -22
drivers/hid/bpf/progs/Huion__Dial-2.bpf.c
··· 214 214 CollectionApplication( 215 215 // -- Byte 0 in report 216 216 ReportId(PAD_REPORT_ID) 217 - LogicalRange_i8(0, 1) 217 + LogicalMaximum_i8(0) 218 + LogicalMaximum_i8(1) 218 219 UsagePage_Digitizers 219 220 Usage_Dig_TabletFunctionKeys 220 221 CollectionPhysical( ··· 235 234 Input(Var|Abs) 236 235 // Byte 4 in report is the dial 237 236 Usage_GD_Wheel 238 - LogicalRange_i8(-1, 1) 237 + LogicalMinimum_i8(-1) 238 + LogicalMaximum_i8(1) 239 239 ReportCount(1) 240 240 ReportSize(8) 241 241 Input(Var|Rel) 242 242 // Byte 5 is the button state 243 243 UsagePage_Button 244 - UsageRange_i8(0x01, 0x8) 245 - LogicalRange_i8(0x0, 0x1) 244 + UsageMinimum_i8(0x01) 245 + UsageMaximum_i8(0x08) 246 + LogicalMinimum_i8(0x0) 247 + LogicalMaximum_i8(0x1) 246 248 ReportCount(7) 247 249 ReportSize(1) 248 250 Input(Var|Abs) ··· 269 265 Usage_Dig_TipSwitch 270 266 Usage_Dig_BarrelSwitch 271 267 Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2 272 - LogicalRange_i8(0, 1) 268 + LogicalMinimum_i8(0) 269 + LogicalMaximum_i8(1) 273 270 ReportSize(1) 274 271 ReportCount(3) 275 272 Input(Var|Abs) ··· 285 280 UsagePage_GenericDesktop 286 281 Unit(cm) 287 282 UnitExponent(-1) 288 - PhysicalRange_i16(0, 266) 289 - LogicalRange_i16(0, 32767) 283 + PhysicalMinimum_i16(0) 284 + PhysicalMaximum_i16(266) 285 + LogicalMinimum_i16(0) 286 + LogicalMaximum_i16(32767) 290 287 Usage_GD_X 291 288 Input(Var|Abs) // Bytes 2+3 292 - PhysicalRange_i16(0, 166) 293 - LogicalRange_i16(0, 32767) 289 + PhysicalMinimum_i16(0) 290 + PhysicalMaximum_i16(166) 291 + LogicalMinimum_i16(0) 292 + LogicalMaximum_i16(32767) 294 293 Usage_GD_Y 295 294 Input(Var|Abs) // Bytes 4+5 296 295 ) 297 296 UsagePage_Digitizers 298 297 Usage_Dig_TipPressure 299 - LogicalRange_i16(0, 8191) 298 + LogicalMinimum_i16(0) 299 + LogicalMaximum_i16(8191) 300 300 Input(Var|Abs) // Byte 6+7 301 301 ReportSize(8) 302 302 ReportCount(2) 303 - LogicalRange_i8(-60, 60) 303 + LogicalMinimum_i8(-60) 304 + LogicalMaximum_i8(60) 304 305 Usage_Dig_XTilt 305 306 Usage_Dig_YTilt 306 307 Input(Var|Abs) // Byte 8+9 ··· 324 313 Usage_Dig_Pen 325 314 CollectionPhysical( 326 315 // Byte 1 are the buttons 327 - LogicalRange_i8(0, 1) 316 + LogicalMinimum_i8(0) 317 + LogicalMaximum_i8(1) 328 318 ReportSize(1) 329 319 Usage_Dig_TipSwitch 330 320 Usage_Dig_BarrelSwitch ··· 345 333 UnitExponent(-1) 346 334 // Note: reported logical range differs 347 335 // from the pen report ID for x and y 348 - LogicalRange_i16(0, 53340) 349 - PhysicalRange_i16(0, 266) 336 + LogicalMinimum_i16(0) 337 + LogicalMaximum_i16(53340) 338 + PhysicalMinimum_i16(0) 339 + PhysicalMaximum_i16(266) 350 340 // Bytes 2/3 in report 351 341 Usage_GD_X 352 342 Input(Var|Abs) 353 - LogicalRange_i16(0, 33340) 354 - PhysicalRange_i16(0, 166) 343 + LogicalMinimum_i16(0) 344 + LogicalMaximum_i16(33340) 345 + PhysicalMinimum_i16(0) 346 + PhysicalMaximum_i16(166) 355 347 // Bytes 4/5 in report 356 348 Usage_GD_Y 357 349 Input(Var|Abs) 358 350 ) 359 351 // Bytes 6/7 in report 360 - LogicalRange_i16(0, 8191) 352 + LogicalMinimum_i16(0) 353 + LogicalMaximum_i16(8191) 361 354 Usage_Dig_TipPressure 362 355 Input(Var|Abs) 363 356 // Bytes 8/9 in report 364 357 ReportCount(1) // Padding 365 358 Input(Const) 366 - LogicalRange_i8(-60, 60) 359 + LogicalMinimum_i8(-60) 360 + LogicalMaximum_i8(60) 367 361 // Byte 10 in report 368 362 Usage_Dig_XTilt 369 363 // Byte 11 in report ··· 384 366 CollectionApplication( 385 367 // Byte 0 386 368 ReportId(PAD_REPORT_ID) 387 - LogicalRange_i8(0, 1) 369 + LogicalMinimum_i8(0) 370 + LogicalMaximum_i8(1) 388 371 UsagePage_Digitizers 389 372 Usage_Dig_TabletFunctionKeys 390 373 CollectionPhysical( ··· 405 386 Input(Var|Abs) 406 387 // Byte 4 is the button state 407 388 UsagePage_Button 408 - UsageRange_i8(0x01, 0x8) 409 - LogicalRange_i8(0x0, 0x1) 389 + UsageMinimum_i8(0x1) 390 + UsageMaximum_i8(0x8) 391 + LogicalMinimum_i8(0x0) 392 + LogicalMaximum_i8(0x1) 410 393 ReportCount(8) 411 394 ReportSize(1) 412 395 Input(Var|Abs) 413 396 // Byte 5 is the top dial 414 397 UsagePage_GenericDesktop 415 398 Usage_GD_Wheel 416 - LogicalRange_i8(-1, 1) 399 + LogicalMinimum_i8(-1) 400 + LogicalMaximum_i8(1) 417 401 ReportCount(1) 418 402 ReportSize(8) 419 403 Input(Var|Rel)
+40 -20
drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c
··· 170 170 CollectionApplication( 171 171 // -- Byte 0 in report 172 172 ReportId(PAD_REPORT_ID) 173 - LogicalRange_i8(0, 1) 173 + LogicalMinimum_i8(0) 174 + LogicalMaximum_i8(1) 174 175 UsagePage_Digitizers 175 176 Usage_Dig_TabletFunctionKeys 176 177 CollectionPhysical( ··· 191 190 Input(Var|Abs) 192 191 // Byte 4 in report is the wheel 193 192 Usage_GD_Wheel 194 - LogicalRange_i8(-1, 1) 193 + LogicalMinimum_i8(-1) 194 + LogicalMaximum_i8(1) 195 195 ReportCount(1) 196 196 ReportSize(8) 197 197 Input(Var|Rel) 198 198 // Byte 5 is the button state 199 199 UsagePage_Button 200 - UsageRange_i8(0x01, 0x6) 201 - LogicalRange_i8(0x01, 0x6) 200 + UsageMinimum_i8(0x1) 201 + UsageMaximum_i8(0x6) 202 + LogicalMinimum_i8(0x1) 203 + LogicalMaximum_i8(0x6) 202 204 ReportCount(1) 203 205 ReportSize(8) 204 206 Input(Arr|Abs) ··· 223 219 Usage_Dig_TipSwitch 224 220 Usage_Dig_BarrelSwitch 225 221 Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2 226 - LogicalRange_i8(0, 1) 222 + LogicalMinimum_i8(0) 223 + LogicalMaximum_i8(1) 227 224 ReportSize(1) 228 225 ReportCount(3) 229 226 Input(Var|Abs) ··· 239 234 UsagePage_GenericDesktop 240 235 Unit(cm) 241 236 UnitExponent(-1) 242 - PhysicalRange_i16(0, 160) 243 - LogicalRange_i16(0, 32767) 237 + PhysicalMinimum_i16(0) 238 + PhysicalMaximum_i16(160) 239 + LogicalMinimum_i16(0) 240 + LogicalMaximum_i16(32767) 244 241 Usage_GD_X 245 242 Input(Var|Abs) // Bytes 2+3 246 - PhysicalRange_i16(0, 100) 247 - LogicalRange_i16(0, 32767) 243 + PhysicalMinimum_i16(0) 244 + PhysicalMaximum_i16(100) 245 + LogicalMinimum_i16(0) 246 + LogicalMaximum_i16(32767) 248 247 Usage_GD_Y 249 248 Input(Var|Abs) // Bytes 4+5 250 249 ) 251 250 UsagePage_Digitizers 252 251 Usage_Dig_TipPressure 253 - LogicalRange_i16(0, 8191) 252 + LogicalMinimum_i16(0) 253 + LogicalMaximum_i16(8191) 254 254 Input(Var|Abs) // Byte 6+7 255 255 // Two bytes padding so we don't need to change the report at all 256 256 ReportSize(8) ··· 275 265 Usage_Dig_Pen 276 266 CollectionPhysical( 277 267 // Byte 1 are the buttons 278 - LogicalRange_i8(0, 1) 268 + LogicalMinimum_i8(0) 269 + LogicalMaximum_i8(1) 279 270 ReportSize(1) 280 271 Usage_Dig_TipSwitch 281 272 Usage_Dig_BarrelSwitch ··· 296 285 UnitExponent(-1) 297 286 // Note: reported logical range differs 298 287 // from the pen report ID for x and y 299 - LogicalRange_i16(0, 32000) 300 - PhysicalRange_i16(0, 160) 288 + LogicalMinimum_i16(0) 289 + LogicalMaximum_i16(32000) 290 + PhysicalMinimum_i16(0) 291 + PhysicalMaximum_i16(160) 301 292 // Bytes 2/3 in report 302 293 Usage_GD_X 303 294 Input(Var|Abs) 304 - LogicalRange_i16(0, 20000) 305 - PhysicalRange_i16(0, 100) 295 + LogicalMinimum_i16(0) 296 + LogicalMaximum_i16(20000) 297 + PhysicalMinimum_i16(0) 298 + PhysicalMaximum_i16(100) 306 299 // Bytes 4/5 in report 307 300 Usage_GD_Y 308 301 Input(Var|Abs) 309 302 ) 310 303 // Bytes 6/7 in report 311 - LogicalRange_i16(0, 8192) 304 + LogicalMinimum_i16(0) 305 + LogicalMaximum_i16(8192) 312 306 Usage_Dig_TipPressure 313 307 Input(Var|Abs) 314 308 ) ··· 323 307 CollectionApplication( 324 308 // Byte 0 325 309 ReportId(PAD_REPORT_ID) 326 - LogicalRange_i8(0, 1) 310 + LogicalMinimum_i8(0) 311 + LogicalMaximum_i8(1) 327 312 UsagePage_Digitizers 328 313 Usage_Dig_TabletFunctionKeys 329 314 CollectionPhysical( ··· 344 327 Input(Var|Abs) 345 328 // Byte 4 is the button state 346 329 UsagePage_Button 347 - UsageRange_i8(0x01, 0x6) 348 - LogicalRange_i8(0x0, 0x1) 330 + UsageMinimum_i8(0x1) 331 + UsageMaximum_i8(0x6) 332 + LogicalMinimum_i8(0x0) 333 + LogicalMaximum_i8(0x1) 349 334 ReportCount(6) 350 335 ReportSize(1) 351 336 Input(Var|Abs) ··· 356 337 // Byte 5 is the wheel 357 338 UsagePage_GenericDesktop 358 339 Usage_GD_Wheel 359 - LogicalRange_i8(-1, 1) 340 + LogicalMinimum_i8(-1) 341 + LogicalMaximum_i8(1) 360 342 ReportCount(1) 361 343 ReportSize(8) 362 344 Input(Var|Rel)
+154
drivers/hid/bpf/progs/Mistel__MD770.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Tatsuyuki Ishi 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 + #define VID_HOLTEK 0x04D9 11 + #define PID_MD770 0x0339 12 + #define RDESC_SIZE 203 13 + 14 + HID_BPF_CONFIG( 15 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HOLTEK, PID_MD770) 16 + ); 17 + 18 + /* 19 + * The Mistel MD770 keyboard reports the first 6 simultaneous key presses 20 + * through the first interface, and anything beyond that through a second 21 + * interface. Unfortunately, the second interface's report descriptor has an 22 + * error, causing events to be malformed and ignored. This HID-BPF driver 23 + * fixes the descriptor to allow NKRO to work again. 24 + * 25 + * For reference, this is the original report descriptor: 26 + * 27 + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 28 + * 0x09, 0x80, // Usage (System Control) 2 29 + * 0xa1, 0x01, // Collection (Application) 4 30 + * 0x85, 0x01, // Report ID (1) 6 31 + * 0x19, 0x81, // Usage Minimum (129) 8 32 + * 0x29, 0x83, // Usage Maximum (131) 10 33 + * 0x15, 0x00, // Logical Minimum (0) 12 34 + * 0x25, 0x01, // Logical Maximum (1) 14 35 + * 0x95, 0x03, // Report Count (3) 16 36 + * 0x75, 0x01, // Report Size (1) 18 37 + * 0x81, 0x02, // Input (Data,Var,Abs) 20 38 + * 0x95, 0x01, // Report Count (1) 22 39 + * 0x75, 0x05, // Report Size (5) 24 40 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 26 41 + * 0xc0, // End Collection 28 42 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 29 43 + * 0x09, 0x01, // Usage (Consumer Control) 31 44 + * 0xa1, 0x01, // Collection (Application) 33 45 + * 0x85, 0x02, // Report ID (2) 35 46 + * 0x15, 0x00, // Logical Minimum (0) 37 47 + * 0x25, 0x01, // Logical Maximum (1) 39 48 + * 0x95, 0x12, // Report Count (18) 41 49 + * 0x75, 0x01, // Report Size (1) 43 50 + * 0x0a, 0x83, 0x01, // Usage (AL Consumer Control Config) 45 51 + * 0x0a, 0x8a, 0x01, // Usage (AL Email Reader) 48 52 + * 0x0a, 0x92, 0x01, // Usage (AL Calculator) 51 53 + * 0x0a, 0x94, 0x01, // Usage (AL Local Machine Browser) 54 54 + * 0x09, 0xcd, // Usage (Play/Pause) 57 55 + * 0x09, 0xb7, // Usage (Stop) 59 56 + * 0x09, 0xb6, // Usage (Scan Previous Track) 61 57 + * 0x09, 0xb5, // Usage (Scan Next Track) 63 58 + * 0x09, 0xe2, // Usage (Mute) 65 59 + * 0x09, 0xea, // Usage (Volume Down) 67 60 + * 0x09, 0xe9, // Usage (Volume Up) 69 61 + * 0x0a, 0x21, 0x02, // Usage (AC Search) 71 62 + * 0x0a, 0x23, 0x02, // Usage (AC Home) 74 63 + * 0x0a, 0x24, 0x02, // Usage (AC Back) 77 64 + * 0x0a, 0x25, 0x02, // Usage (AC Forward) 80 65 + * 0x0a, 0x26, 0x02, // Usage (AC Stop) 83 66 + * 0x0a, 0x27, 0x02, // Usage (AC Refresh) 86 67 + * 0x0a, 0x2a, 0x02, // Usage (AC Bookmarks) 89 68 + * 0x81, 0x02, // Input (Data,Var,Abs) 92 69 + * 0x95, 0x01, // Report Count (1) 94 70 + * 0x75, 0x0e, // Report Size (14) 96 71 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 98 72 + * 0xc0, // End Collection 100 73 + * 0x05, 0x01, // Usage Page (Generic Desktop) 101 74 + * 0x09, 0x02, // Usage (Mouse) 103 75 + * 0xa1, 0x01, // Collection (Application) 105 76 + * 0x09, 0x01, // Usage (Pointer) 107 77 + * 0xa1, 0x00, // Collection (Physical) 109 78 + * 0x85, 0x03, // Report ID (3) 111 79 + * 0x05, 0x09, // Usage Page (Button) 113 80 + * 0x19, 0x01, // Usage Minimum (1) 115 81 + * 0x29, 0x08, // Usage Maximum (8) 117 82 + * 0x15, 0x00, // Logical Minimum (0) 119 83 + * 0x25, 0x01, // Logical Maximum (1) 121 84 + * 0x75, 0x01, // Report Size (1) 123 85 + * 0x95, 0x08, // Report Count (8) 125 86 + * 0x81, 0x02, // Input (Data,Var,Abs) 127 87 + * 0x05, 0x01, // Usage Page (Generic Desktop) 129 88 + * 0x09, 0x30, // Usage (X) 131 89 + * 0x09, 0x31, // Usage (Y) 133 90 + * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 135 91 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 138 92 + * 0x75, 0x10, // Report Size (16) 141 93 + * 0x95, 0x02, // Report Count (2) 143 94 + * 0x81, 0x06, // Input (Data,Var,Rel) 145 95 + * 0x09, 0x38, // Usage (Wheel) 147 96 + * 0x15, 0x81, // Logical Minimum (-127) 149 97 + * 0x25, 0x7f, // Logical Maximum (127) 151 98 + * 0x75, 0x08, // Report Size (8) 153 99 + * 0x95, 0x01, // Report Count (1) 155 100 + * 0x81, 0x06, // Input (Data,Var,Rel) 157 101 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 159 102 + * 0x0a, 0x38, 0x02, // Usage (AC Pan) 161 103 + * 0x95, 0x01, // Report Count (1) 164 104 + * 0x81, 0x06, // Input (Data,Var,Rel) 166 105 + * 0xc0, // End Collection 168 106 + * 0xc0, // End Collection 169 107 + * 0x05, 0x01, // Usage Page (Generic Desktop) 170 108 + * 0x09, 0x06, // Usage (Keyboard) 172 109 + * 0xa1, 0x01, // Collection (Application) 174 110 + * 0x85, 0x04, // Report ID (4) 176 111 + * 0x05, 0x07, // Usage Page (Keyboard) 178 112 + * 0x95, 0x01, // Report Count (1) 180 113 + * 0x75, 0x08, // Report Size (8) 182 114 + * 0x81, 0x03, // Input (Cnst,Var,Abs) 184 115 + * 0x95, 0xe8, // Report Count (232) 186 116 + * 0x75, 0x01, // Report Size (1) 188 117 + * 0x15, 0x00, // Logical Minimum (0) 190 118 + * 0x25, 0x01, // Logical Maximum (1) 192 119 + * 0x05, 0x07, // Usage Page (Keyboard) 194 120 + * 0x19, 0x00, // Usage Minimum (0) 196 121 + * 0x29, 0xe7, // Usage Maximum (231) 198 122 + * 0x81, 0x00, // Input (Data,Arr,Abs) 200 <- change to 0x81, 0x02 (Data,Var,Abs) 123 + * 0xc0, // End Collection 202 124 + */ 125 + 126 + SEC(HID_BPF_RDESC_FIXUP) 127 + int BPF_PROG(hid_rdesc_fixup_mistel_md770, struct hid_bpf_ctx *hctx) 128 + { 129 + __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE); 130 + 131 + if (!data) 132 + return 0; /* EPERM check */ 133 + 134 + if (data[201] == 0x00) 135 + data[201] = 0x02; 136 + 137 + return 0; 138 + } 139 + 140 + HID_BPF_OPS(mistel_md770) = { 141 + .hid_rdesc_fixup = (void *)hid_rdesc_fixup_mistel_md770, 142 + }; 143 + 144 + SEC("syscall") 145 + int probe(struct hid_bpf_probe_args *ctx) 146 + { 147 + ctx->retval = ctx->rdesc_size != RDESC_SIZE; 148 + if (ctx->retval) 149 + ctx->retval = -EINVAL; 150 + 151 + return 0; 152 + } 153 + 154 + char _license[] SEC("license") = "GPL";
+148
drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2024 José Expósito 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 + #define VID_RAPOO 0x24AE 11 + #define PID_M50 0x2015 12 + #define RDESC_SIZE 186 13 + 14 + HID_BPF_CONFIG( 15 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_RAPOO, PID_M50) 16 + ); 17 + 18 + /* 19 + * The Rapoo M50 Plus Silent mouse has 2 side buttons in addition to the left, 20 + * right and middle buttons. However, its original HID descriptor has a Usage 21 + * Maximum of 3, preventing the side buttons to work. This HID-BPF driver 22 + * changes that usage to 5. 23 + * 24 + * For reference, this is the original report descriptor: 25 + * 26 + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 27 + * 0x09, 0x02, // Usage (Mouse) 2 28 + * 0xa1, 0x01, // Collection (Application) 4 29 + * 0x85, 0x01, // Report ID (1) 6 30 + * 0x09, 0x01, // Usage (Pointer) 8 31 + * 0xa1, 0x00, // Collection (Physical) 10 32 + * 0x05, 0x09, // Usage Page (Button) 12 33 + * 0x19, 0x01, // Usage Minimum (1) 14 34 + * 0x29, 0x03, // Usage Maximum (3) 16 <- change to 0x05 35 + * 0x15, 0x00, // Logical Minimum (0) 18 36 + * 0x25, 0x01, // Logical Maximum (1) 20 37 + * 0x75, 0x01, // Report Size (1) 22 38 + * 0x95, 0x05, // Report Count (5) 24 39 + * 0x81, 0x02, // Input (Data,Var,Abs) 26 40 + * 0x75, 0x03, // Report Size (3) 28 41 + * 0x95, 0x01, // Report Count (1) 30 42 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 32 43 + * 0x05, 0x01, // Usage Page (Generic Desktop) 34 44 + * 0x09, 0x30, // Usage (X) 36 45 + * 0x09, 0x31, // Usage (Y) 38 46 + * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 40 47 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 43 48 + * 0x75, 0x10, // Report Size (16) 46 49 + * 0x95, 0x02, // Report Count (2) 48 50 + * 0x81, 0x06, // Input (Data,Var,Rel) 50 51 + * 0x09, 0x38, // Usage (Wheel) 52 52 + * 0x15, 0x81, // Logical Minimum (-127) 54 53 + * 0x25, 0x7f, // Logical Maximum (127) 56 54 + * 0x75, 0x08, // Report Size (8) 58 55 + * 0x95, 0x01, // Report Count (1) 60 56 + * 0x81, 0x06, // Input (Data,Var,Rel) 62 57 + * 0xc0, // End Collection 64 58 + * 0xc0, // End Collection 65 59 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 66 60 + * 0x09, 0x01, // Usage (Consumer Control) 68 61 + * 0xa1, 0x01, // Collection (Application) 70 62 + * 0x85, 0x02, // Report ID (2) 72 63 + * 0x75, 0x10, // Report Size (16) 74 64 + * 0x95, 0x01, // Report Count (1) 76 65 + * 0x15, 0x01, // Logical Minimum (1) 78 66 + * 0x26, 0x8c, 0x02, // Logical Maximum (652) 80 67 + * 0x19, 0x01, // Usage Minimum (1) 83 68 + * 0x2a, 0x8c, 0x02, // Usage Maximum (652) 85 69 + * 0x81, 0x00, // Input (Data,Arr,Abs) 88 70 + * 0xc0, // End Collection 90 71 + * 0x05, 0x01, // Usage Page (Generic Desktop) 91 72 + * 0x09, 0x80, // Usage (System Control) 93 73 + * 0xa1, 0x01, // Collection (Application) 95 74 + * 0x85, 0x03, // Report ID (3) 97 75 + * 0x09, 0x82, // Usage (System Sleep) 99 76 + * 0x09, 0x81, // Usage (System Power Down) 101 77 + * 0x09, 0x83, // Usage (System Wake Up) 103 78 + * 0x15, 0x00, // Logical Minimum (0) 105 79 + * 0x25, 0x01, // Logical Maximum (1) 107 80 + * 0x19, 0x01, // Usage Minimum (1) 109 81 + * 0x29, 0x03, // Usage Maximum (3) 111 82 + * 0x75, 0x01, // Report Size (1) 113 83 + * 0x95, 0x03, // Report Count (3) 115 84 + * 0x81, 0x02, // Input (Data,Var,Abs) 117 85 + * 0x95, 0x05, // Report Count (5) 119 86 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 121 87 + * 0xc0, // End Collection 123 88 + * 0x05, 0x01, // Usage Page (Generic Desktop) 124 89 + * 0x09, 0x00, // Usage (Undefined) 126 90 + * 0xa1, 0x01, // Collection (Application) 128 91 + * 0x85, 0x05, // Report ID (5) 130 92 + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 132 93 + * 0x09, 0x01, // Usage (Vendor Usage 1) 135 94 + * 0x15, 0x81, // Logical Minimum (-127) 137 95 + * 0x25, 0x7f, // Logical Maximum (127) 139 96 + * 0x75, 0x08, // Report Size (8) 141 97 + * 0x95, 0x07, // Report Count (7) 143 98 + * 0xb1, 0x02, // Feature (Data,Var,Abs) 145 99 + * 0xc0, // End Collection 147 100 + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 148 101 + * 0x09, 0x0e, // Usage (Vendor Usage 0x0e) 151 102 + * 0xa1, 0x01, // Collection (Application) 153 103 + * 0x85, 0xba, // Report ID (186) 155 104 + * 0x95, 0x1f, // Report Count (31) 157 105 + * 0x75, 0x08, // Report Size (8) 159 106 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 161 107 + * 0x15, 0x00, // Logical Minimum (0) 164 108 + * 0x09, 0x01, // Usage (Vendor Usage 1) 166 109 + * 0x91, 0x02, // Output (Data,Var,Abs) 168 110 + * 0x85, 0xba, // Report ID (186) 170 111 + * 0x95, 0x1f, // Report Count (31) 172 112 + * 0x75, 0x08, // Report Size (8) 174 113 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 176 114 + * 0x15, 0x00, // Logical Minimum (0) 179 115 + * 0x09, 0x01, // Usage (Vendor Usage 1) 181 116 + * 0x81, 0x02, // Input (Data,Var,Abs) 183 117 + * 0xc0, // End Collection 185 118 + */ 119 + 120 + SEC(HID_BPF_RDESC_FIXUP) 121 + int BPF_PROG(hid_rdesc_fixup_rapoo_m50, struct hid_bpf_ctx *hctx) 122 + { 123 + __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE); 124 + 125 + if (!data) 126 + return 0; /* EPERM check */ 127 + 128 + if (data[17] == 0x03) 129 + data[17] = 0x05; 130 + 131 + return 0; 132 + } 133 + 134 + HID_BPF_OPS(rapoo_m50) = { 135 + .hid_rdesc_fixup = (void *)hid_rdesc_fixup_rapoo_m50, 136 + }; 137 + 138 + SEC("syscall") 139 + int probe(struct hid_bpf_probe_args *ctx) 140 + { 141 + ctx->retval = ctx->rdesc_size != RDESC_SIZE; 142 + if (ctx->retval) 143 + ctx->retval = -EINVAL; 144 + 145 + return 0; 146 + } 147 + 148 + char _license[] SEC("license") = "GPL";
+27 -9
drivers/hid/bpf/progs/hid_report_helpers.h
··· 52 52 * Usage_GD_Keyboard 53 53 * CollectionApplication( ← Open the collection 54 54 * ReportId(3) 55 - * LogicalRange_i8(0, 1) 55 + * LogicalMinimum_i8(0) 56 + * LogicalMaximum_i8(1) 56 57 * // other fields 57 58 * ) ← End EndCollection 58 59 * ··· 75 74 #define Arr 0x0 76 75 #define Abs 0x0 77 76 #define Rel 0x4 77 + #define Null 0x40 78 + #define Buff 0x0100 78 79 79 80 /* Use like this: Input(Var|Abs) */ 80 81 #define Input(i_) 0x081, i8(i_), 81 82 #define Output(i_) 0x091, i8(i_), 82 83 #define Feature(i_) 0x0b1, i8(i_), 83 84 85 + #define Input_i16(i_) 0x082, LE16(i_), 86 + #define Output_i16(i_) 0x092, LE16(i_), 87 + #define Feature_i16(i_) 0x0b2, LE16(i_), 88 + 84 89 #define ReportId(id_) 0x85, i8(id_), 85 90 #define ReportSize(sz_) 0x75, i8(sz_), 86 91 #define ReportCount(cnt_) 0x95, i8(cnt_), 87 92 88 - #define LogicalRange_i8(min_, max_) 0x15, i8(min_), 0x25, i8(max_), 89 - #define LogicalRange_i16(min_, max_) 0x16, LE16(min_), 0x26, LE16(max_), 90 - #define LogicalRange_i32(min_, max_) 0x17, LE32(min_), 0x27, LE32(max_), 93 + #define LogicalMinimum_i8(min_) 0x15, i8(min_), 94 + #define LogicalMinimum_i16(min_) 0x16, LE16(min_), 95 + #define LogicalMinimum_i32(min_) 0x17, LE32(min_), 91 96 92 - #define PhysicalRange_i8(min_, max_) 0x35, i8(min_), 0x45, i8(max_), 93 - #define PhysicalRange_i16(min_, max_) 0x36, LE16(min_), 0x46, LE16(max_), 94 - #define PhysicalRange_i32(min_, max_) 0x37, LE32(min_), 0x47, LE32(max_), 97 + #define LogicalMaximum_i8(max_) 0x25, i8(max_), 98 + #define LogicalMaximum_i16(max_) 0x26, LE16(max_), 99 + #define LogicalMaximum_i32(max_) 0x27, LE32(max_), 95 100 96 - #define UsageRange_i8(min_, max_) 0x19, i8(min_), 0x29, i8(max_), 97 - #define UsageRange_i16(min_, max_) 0x1a, LE16(min_), 0x2a, LE16(max_), 101 + #define PhysicalMinimum_i8(min_) 0x35, i8(min_), 102 + #define PhysicalMinimum_i16(min_) 0x36, LE16(min_), 103 + #define PhysicalMinimum_i32(min_) 0x37, LE32(min_), 104 + 105 + #define PhysicalMaximum_i8(max_) 0x45, i8(max_), 106 + #define PhysicalMaximum_i16(max_) 0x46, LE16(max_), 107 + #define PhysicalMaximum_i32(max_) 0x47, LE32(max_), 108 + 109 + #define UsageMinimum_i8(min_) 0x19, i8(min_), 110 + #define UsageMinimum_i16(min_) 0x1a, LE16(min_), 111 + 112 + #define UsageMaximum_i8(max_) 0x29, i8(max_), 113 + #define UsageMaximum_i16(max_) 0x2a, LE16(max_), 98 114 99 115 #define UsagePage_i8(p_) 0x05, i8(p_), 100 116 #define UsagePage_i16(p_) 0x06, LE16(p_),
+1 -1
drivers/hid/hid-asus.c
··· 1183 1183 1184 1184 if (drvdata->quirks & QUIRK_G752_KEYBOARD && 1185 1185 *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) { 1186 - /* report is missing usage mninum and maximum */ 1186 + /* report is missing usage minimum and maximum */ 1187 1187 __u8 *new_rdesc; 1188 1188 size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc); 1189 1189
+105 -77
drivers/hid/hid-core.c
··· 46 46 MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver"); 47 47 48 48 /* 49 + * Convert a signed n-bit integer to signed 32-bit integer. 50 + */ 51 + 52 + static s32 snto32(__u32 value, unsigned int n) 53 + { 54 + if (!value || !n) 55 + return 0; 56 + 57 + if (n > 32) 58 + n = 32; 59 + 60 + return sign_extend32(value, n - 1); 61 + } 62 + 63 + /* 64 + * Convert a signed 32-bit integer to a signed n-bit integer. 65 + */ 66 + 67 + static u32 s32ton(__s32 value, unsigned int n) 68 + { 69 + s32 a = value >> (n - 1); 70 + 71 + if (a && a != -1) 72 + return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; 73 + return value & ((1 << n) - 1); 74 + } 75 + 76 + /* 49 77 * Register a new report for a device. 50 78 */ 51 79 ··· 453 425 * both this and the standard encoding. */ 454 426 raw_value = item_sdata(item); 455 427 if (!(raw_value & 0xfffffff0)) 456 - parser->global.unit_exponent = hid_snto32(raw_value, 4); 428 + parser->global.unit_exponent = snto32(raw_value, 4); 457 429 else 458 430 parser->global.unit_exponent = raw_value; 459 431 return 0; ··· 713 685 INIT_LIST_HEAD(&report_enum->report_list); 714 686 } 715 687 716 - kfree(device->rdesc); 688 + /* 689 + * If the HID driver had a rdesc_fixup() callback, dev->rdesc 690 + * will be allocated by hid-core and needs to be freed. 691 + * Otherwise, it is either equal to dev_rdesc or bpf_rdesc, in 692 + * which cases it'll be freed later on device removal or destroy. 693 + */ 694 + if (device->rdesc != device->dev_rdesc && device->rdesc != device->bpf_rdesc) 695 + kfree(device->rdesc); 717 696 device->rdesc = NULL; 718 697 device->rsize = 0; 719 698 ··· 733 698 device->status &= ~HID_STAT_PARSED; 734 699 } 735 700 701 + static inline void hid_free_bpf_rdesc(struct hid_device *hdev) 702 + { 703 + /* bpf_rdesc is either equal to dev_rdesc or allocated by call_hid_bpf_rdesc_fixup() */ 704 + if (hdev->bpf_rdesc != hdev->dev_rdesc) 705 + kfree(hdev->bpf_rdesc); 706 + hdev->bpf_rdesc = NULL; 707 + } 708 + 736 709 /* 737 710 * Free a device structure, all reports, and all fields. 738 711 */ ··· 750 707 struct hid_device *hid = container_of(ref, struct hid_device, ref); 751 708 752 709 hid_close_report(hid); 710 + hid_free_bpf_rdesc(hid); 753 711 kfree(hid->dev_rdesc); 754 712 kfree(hid); 755 713 } ··· 798 754 } 799 755 800 756 item->format = HID_ITEM_FORMAT_SHORT; 801 - item->size = b & 3; 757 + item->size = BIT(b & 3) >> 1; /* 0, 1, 2, 3 -> 0, 1, 2, 4 */ 758 + 759 + if (end - start < item->size) 760 + return NULL; 802 761 803 762 switch (item->size) { 804 763 case 0: 805 - return start; 764 + break; 806 765 807 766 case 1: 808 - if ((end - start) < 1) 809 - return NULL; 810 - item->data.u8 = *start++; 811 - return start; 767 + item->data.u8 = *start; 768 + break; 812 769 813 770 case 2: 814 - if ((end - start) < 2) 815 - return NULL; 816 771 item->data.u16 = get_unaligned_le16(start); 817 - start = (__u8 *)((__le16 *)start + 1); 818 - return start; 772 + break; 819 773 820 - case 3: 821 - item->size++; 822 - if ((end - start) < 4) 823 - return NULL; 774 + case 4: 824 775 item->data.u32 = get_unaligned_le32(start); 825 - start = (__u8 *)((__le32 *)start + 1); 826 - return start; 776 + break; 827 777 } 828 778 829 - return NULL; 779 + return start + item->size; 830 780 } 831 781 832 782 static void hid_scan_input_usage(struct hid_parser *parser, u32 usage) ··· 1243 1205 struct hid_item item; 1244 1206 unsigned int size; 1245 1207 const __u8 *start; 1246 - __u8 *buf; 1247 1208 const __u8 *end; 1248 1209 const __u8 *next; 1249 1210 int ret; ··· 1258 1221 if (WARN_ON(device->status & HID_STAT_PARSED)) 1259 1222 return -EBUSY; 1260 1223 1261 - start = device->dev_rdesc; 1224 + start = device->bpf_rdesc; 1262 1225 if (WARN_ON(!start)) 1263 1226 return -ENODEV; 1264 - size = device->dev_rsize; 1227 + size = device->bpf_rsize; 1265 1228 1266 - /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */ 1267 - buf = call_hid_bpf_rdesc_fixup(device, start, &size); 1268 - if (buf == NULL) 1269 - return -ENOMEM; 1229 + if (device->driver->report_fixup) { 1230 + /* 1231 + * device->driver->report_fixup() needs to work 1232 + * on a copy of our report descriptor so it can 1233 + * change it. 1234 + */ 1235 + __u8 *buf = kmemdup(start, size, GFP_KERNEL); 1270 1236 1271 - if (device->driver->report_fixup) 1237 + if (buf == NULL) 1238 + return -ENOMEM; 1239 + 1272 1240 start = device->driver->report_fixup(device, buf, &size); 1273 - else 1274 - start = buf; 1275 1241 1276 - start = kmemdup(start, size, GFP_KERNEL); 1277 - kfree(buf); 1278 - if (start == NULL) 1279 - return -ENOMEM; 1242 + /* 1243 + * The second kmemdup is required in case report_fixup() returns 1244 + * a static read-only memory, but we have no idea if that memory 1245 + * needs to be cleaned up or not at the end. 1246 + */ 1247 + start = kmemdup(start, size, GFP_KERNEL); 1248 + kfree(buf); 1249 + if (start == NULL) 1250 + return -ENOMEM; 1251 + } 1280 1252 1281 1253 device->rdesc = start; 1282 1254 device->rsize = size; ··· 1360 1314 return ret; 1361 1315 } 1362 1316 EXPORT_SYMBOL_GPL(hid_open_report); 1363 - 1364 - /* 1365 - * Convert a signed n-bit integer to signed 32-bit integer. Common 1366 - * cases are done through the compiler, the screwed things has to be 1367 - * done by hand. 1368 - */ 1369 - 1370 - static s32 snto32(__u32 value, unsigned n) 1371 - { 1372 - if (!value || !n) 1373 - return 0; 1374 - 1375 - if (n > 32) 1376 - n = 32; 1377 - 1378 - switch (n) { 1379 - case 8: return ((__s8)value); 1380 - case 16: return ((__s16)value); 1381 - case 32: return ((__s32)value); 1382 - } 1383 - return value & (1 << (n - 1)) ? value | (~0U << n) : value; 1384 - } 1385 - 1386 - s32 hid_snto32(__u32 value, unsigned n) 1387 - { 1388 - return snto32(value, n); 1389 - } 1390 - EXPORT_SYMBOL_GPL(hid_snto32); 1391 - 1392 - /* 1393 - * Convert a signed 32-bit integer to a signed n-bit integer. 1394 - */ 1395 - 1396 - static u32 s32ton(__s32 value, unsigned n) 1397 - { 1398 - s32 a = value >> (n - 1); 1399 - if (a && a != -1) 1400 - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; 1401 - return value & ((1 << n) - 1); 1402 - } 1403 1317 1404 1318 /* 1405 1319 * Extract/implement a data field from/to a little endian report (bit array). ··· 2680 2674 /* 2681 2675 * hid-generic implements .match(), so we must be dealing with a 2682 2676 * different HID driver here, and can simply check if 2683 - * hid_ignore_special_drivers is set or not. 2677 + * hid_ignore_special_drivers or HID_QUIRK_IGNORE_SPECIAL_DRIVER 2678 + * are set or not. 2684 2679 */ 2685 - return !hid_ignore_special_drivers; 2680 + return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER); 2686 2681 } 2687 2682 2688 2683 static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) 2689 2684 { 2690 2685 const struct hid_device_id *id; 2691 2686 int ret; 2687 + 2688 + if (!hdev->bpf_rsize) { 2689 + unsigned int quirks; 2690 + 2691 + /* reset the quirks that has been previously set */ 2692 + quirks = hid_lookup_quirk(hdev); 2693 + hdev->quirks = quirks; 2694 + 2695 + /* in case a bpf program gets detached, we need to free the old one */ 2696 + hid_free_bpf_rdesc(hdev); 2697 + 2698 + /* keep this around so we know we called it once */ 2699 + hdev->bpf_rsize = hdev->dev_rsize; 2700 + 2701 + /* call_hid_bpf_rdesc_fixup will always return a valid pointer */ 2702 + hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc, 2703 + &hdev->bpf_rsize); 2704 + if (quirks ^ hdev->quirks) 2705 + hid_info(hdev, "HID-BPF toggled quirks on the device: %04x", 2706 + quirks ^ hdev->quirks); 2707 + } 2692 2708 2693 2709 if (!hid_check_device_match(hdev, hdrv, &id)) 2694 2710 return -ENODEV; ··· 2719 2691 if (!hdev->devres_group_id) 2720 2692 return -ENOMEM; 2721 2693 2722 - /* reset the quirks that has been previously set */ 2723 - hdev->quirks = hid_lookup_quirk(hdev); 2724 2694 hdev->driver = hdrv; 2725 2695 2726 2696 if (hdrv->probe) { ··· 2966 2940 hid_debug_unregister(hdev); 2967 2941 hdev->status &= ~HID_STAT_ADDED; 2968 2942 } 2943 + hid_free_bpf_rdesc(hdev); 2969 2944 kfree(hdev->dev_rdesc); 2970 2945 hdev->dev_rdesc = NULL; 2971 2946 hdev->dev_rsize = 0; 2947 + hdev->bpf_rsize = 0; 2972 2948 } 2973 2949 2974 2950 /**
+829
drivers/hid/hid-corsair-void.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * HID driver for Corsair Void headsets 4 + * 5 + * Copyright (C) 2023-2024 Stuart Hayhurst 6 + */ 7 + 8 + /* -------------------------------------------------------------------------- */ 9 + /* Receiver report information: (ID 100) */ 10 + /* -------------------------------------------------------------------------- */ 11 + /* 12 + * When queried, the receiver reponds with 5 bytes to describe the battery 13 + * The power button, mute button and moving the mic also trigger this report 14 + * This includes power button + mic + connection + battery status and capacity 15 + * The information below may not be perfect, it's been gathered through guesses 16 + * 17 + * 0: REPORT ID 18 + * 100 for the battery packet 19 + * 20 + * 1: POWER BUTTON + (?) 21 + * Largest bit is 1 when power button pressed 22 + * 23 + * 2: BATTERY CAPACITY + MIC STATUS 24 + * Battery capacity: 25 + * Seems to report ~54 higher than reality when charging 26 + * Capped at 100, charging or not 27 + * Microphone status: 28 + * Largest bit is set to 1 when the mic is physically up 29 + * No bits change when the mic is muted, only when physically moved 30 + * This report is sent every time the mic is moved, no polling required 31 + * 32 + * 3: CONNECTION STATUS 33 + * 16: Wired headset 34 + * 38: Initialising 35 + * 49: Lost connection 36 + * 51: Disconnected, searching 37 + * 52: Disconnected, not searching 38 + * 177: Normal 39 + * 40 + * 4: BATTERY STATUS 41 + * 0: Disconnected 42 + * 1: Normal 43 + * 2: Low 44 + * 3: Critical - sent during shutdown 45 + * 4: Fully charged 46 + * 5: Charging 47 + */ 48 + /* -------------------------------------------------------------------------- */ 49 + 50 + /* -------------------------------------------------------------------------- */ 51 + /* Receiver report information: (ID 102) */ 52 + /* -------------------------------------------------------------------------- */ 53 + /* 54 + * When queried, the recevier responds with 4 bytes to describe the firmware 55 + * The first 2 bytes are for the receiver, the second 2 are the headset 56 + * The headset firmware version will be 0 if no headset is connected 57 + * 58 + * 0: Recevier firmware major version 59 + * Major version of the receiver's firmware 60 + * 61 + * 1: Recevier firmware minor version 62 + * Minor version of the receiver's firmware 63 + * 64 + * 2: Headset firmware major version 65 + * Major version of the headset's firmware 66 + * 67 + * 3: Headset firmware minor version 68 + * Minor version of the headset's firmware 69 + */ 70 + /* -------------------------------------------------------------------------- */ 71 + 72 + #include <linux/bitfield.h> 73 + #include <linux/bitops.h> 74 + #include <linux/cleanup.h> 75 + #include <linux/device.h> 76 + #include <linux/hid.h> 77 + #include <linux/module.h> 78 + #include <linux/mutex.h> 79 + #include <linux/power_supply.h> 80 + #include <linux/usb.h> 81 + #include <linux/workqueue.h> 82 + #include <asm/byteorder.h> 83 + 84 + #include "hid-ids.h" 85 + 86 + #define CORSAIR_VOID_DEVICE(id, type) { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, (id)), \ 87 + .driver_data = (type) } 88 + #define CORSAIR_VOID_WIRELESS_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRELESS) 89 + #define CORSAIR_VOID_WIRED_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRED) 90 + 91 + #define CORSAIR_VOID_STATUS_REQUEST_ID 0xC9 92 + #define CORSAIR_VOID_NOTIF_REQUEST_ID 0xCA 93 + #define CORSAIR_VOID_SIDETONE_REQUEST_ID 0xFF 94 + #define CORSAIR_VOID_STATUS_REPORT_ID 0x64 95 + #define CORSAIR_VOID_FIRMWARE_REPORT_ID 0x66 96 + 97 + #define CORSAIR_VOID_USB_SIDETONE_REQUEST 0x1 98 + #define CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE 0x21 99 + #define CORSAIR_VOID_USB_SIDETONE_VALUE 0x200 100 + #define CORSAIR_VOID_USB_SIDETONE_INDEX 0xB00 101 + 102 + #define CORSAIR_VOID_MIC_MASK GENMASK(7, 7) 103 + #define CORSAIR_VOID_CAPACITY_MASK GENMASK(6, 0) 104 + 105 + #define CORSAIR_VOID_WIRELESS_CONNECTED 177 106 + 107 + #define CORSAIR_VOID_SIDETONE_MAX_WIRELESS 55 108 + #define CORSAIR_VOID_SIDETONE_MAX_WIRED 4096 109 + 110 + enum { 111 + CORSAIR_VOID_WIRELESS, 112 + CORSAIR_VOID_WIRED, 113 + }; 114 + 115 + enum { 116 + CORSAIR_VOID_BATTERY_NORMAL = 1, 117 + CORSAIR_VOID_BATTERY_LOW = 2, 118 + CORSAIR_VOID_BATTERY_CRITICAL = 3, 119 + CORSAIR_VOID_BATTERY_CHARGED = 4, 120 + CORSAIR_VOID_BATTERY_CHARGING = 5, 121 + }; 122 + 123 + static enum power_supply_property corsair_void_battery_props[] = { 124 + POWER_SUPPLY_PROP_STATUS, 125 + POWER_SUPPLY_PROP_PRESENT, 126 + POWER_SUPPLY_PROP_CAPACITY, 127 + POWER_SUPPLY_PROP_CAPACITY_LEVEL, 128 + POWER_SUPPLY_PROP_SCOPE, 129 + POWER_SUPPLY_PROP_MODEL_NAME, 130 + POWER_SUPPLY_PROP_MANUFACTURER, 131 + }; 132 + 133 + struct corsair_void_battery_data { 134 + int status; 135 + bool present; 136 + int capacity; 137 + int capacity_level; 138 + }; 139 + 140 + struct corsair_void_drvdata { 141 + struct hid_device *hid_dev; 142 + struct device *dev; 143 + 144 + char *name; 145 + bool is_wired; 146 + unsigned int sidetone_max; 147 + 148 + struct corsair_void_battery_data battery_data; 149 + bool mic_up; 150 + bool connected; 151 + int fw_receiver_major; 152 + int fw_receiver_minor; 153 + int fw_headset_major; 154 + int fw_headset_minor; 155 + 156 + struct power_supply *battery; 157 + struct power_supply_desc battery_desc; 158 + struct mutex battery_mutex; 159 + 160 + struct delayed_work delayed_status_work; 161 + struct delayed_work delayed_firmware_work; 162 + struct work_struct battery_remove_work; 163 + struct work_struct battery_add_work; 164 + }; 165 + 166 + /* 167 + * Functions to process receiver data 168 + */ 169 + 170 + static void corsair_void_set_wireless_status(struct corsair_void_drvdata *drvdata) 171 + { 172 + struct usb_interface *usb_if = to_usb_interface(drvdata->dev->parent); 173 + 174 + if (drvdata->is_wired) 175 + return; 176 + 177 + usb_set_wireless_status(usb_if, drvdata->connected ? 178 + USB_WIRELESS_STATUS_CONNECTED : 179 + USB_WIRELESS_STATUS_DISCONNECTED); 180 + } 181 + 182 + static void corsair_void_set_unknown_batt(struct corsair_void_drvdata *drvdata) 183 + { 184 + struct corsair_void_battery_data *battery_data = &drvdata->battery_data; 185 + 186 + battery_data->status = POWER_SUPPLY_STATUS_UNKNOWN; 187 + battery_data->present = false; 188 + battery_data->capacity = 0; 189 + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 190 + } 191 + 192 + /* Reset data that may change between wireless connections */ 193 + static void corsair_void_set_unknown_wireless_data(struct corsair_void_drvdata *drvdata) 194 + { 195 + /* Only 0 out headset, receiver is always known if relevant */ 196 + drvdata->fw_headset_major = 0; 197 + drvdata->fw_headset_minor = 0; 198 + 199 + drvdata->connected = false; 200 + drvdata->mic_up = false; 201 + 202 + corsair_void_set_wireless_status(drvdata); 203 + } 204 + 205 + static void corsair_void_process_receiver(struct corsair_void_drvdata *drvdata, 206 + int raw_battery_capacity, 207 + int raw_connection_status, 208 + int raw_battery_status) 209 + { 210 + struct corsair_void_battery_data *battery_data = &drvdata->battery_data; 211 + struct corsair_void_battery_data orig_battery_data; 212 + 213 + /* Save initial battery data, to compare later */ 214 + orig_battery_data = *battery_data; 215 + 216 + /* Headset not connected, or it's wired */ 217 + if (raw_connection_status != CORSAIR_VOID_WIRELESS_CONNECTED) 218 + goto unknown_battery; 219 + 220 + /* Battery information unavailable */ 221 + if (raw_battery_status == 0) 222 + goto unknown_battery; 223 + 224 + /* Battery must be connected then */ 225 + battery_data->present = true; 226 + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 227 + 228 + /* Set battery status */ 229 + switch (raw_battery_status) { 230 + case CORSAIR_VOID_BATTERY_NORMAL: 231 + case CORSAIR_VOID_BATTERY_LOW: 232 + case CORSAIR_VOID_BATTERY_CRITICAL: 233 + battery_data->status = POWER_SUPPLY_STATUS_DISCHARGING; 234 + if (raw_battery_status == CORSAIR_VOID_BATTERY_LOW) 235 + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 236 + else if (raw_battery_status == CORSAIR_VOID_BATTERY_CRITICAL) 237 + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 238 + 239 + break; 240 + case CORSAIR_VOID_BATTERY_CHARGED: 241 + battery_data->status = POWER_SUPPLY_STATUS_FULL; 242 + break; 243 + case CORSAIR_VOID_BATTERY_CHARGING: 244 + battery_data->status = POWER_SUPPLY_STATUS_CHARGING; 245 + break; 246 + default: 247 + hid_warn(drvdata->hid_dev, "unknown battery status '%d'", 248 + raw_battery_status); 249 + goto unknown_battery; 250 + break; 251 + } 252 + 253 + battery_data->capacity = raw_battery_capacity; 254 + corsair_void_set_wireless_status(drvdata); 255 + 256 + goto success; 257 + unknown_battery: 258 + corsair_void_set_unknown_batt(drvdata); 259 + success: 260 + 261 + /* Inform power supply if battery values changed */ 262 + if (memcmp(&orig_battery_data, battery_data, sizeof(*battery_data))) { 263 + scoped_guard(mutex, &drvdata->battery_mutex) { 264 + if (drvdata->battery) { 265 + power_supply_changed(drvdata->battery); 266 + } 267 + } 268 + } 269 + } 270 + 271 + /* 272 + * Functions to report stored data 273 + */ 274 + 275 + static int corsair_void_battery_get_property(struct power_supply *psy, 276 + enum power_supply_property prop, 277 + union power_supply_propval *val) 278 + { 279 + struct corsair_void_drvdata *drvdata = power_supply_get_drvdata(psy); 280 + 281 + switch (prop) { 282 + case POWER_SUPPLY_PROP_SCOPE: 283 + val->intval = POWER_SUPPLY_SCOPE_DEVICE; 284 + break; 285 + case POWER_SUPPLY_PROP_MODEL_NAME: 286 + if (!strncmp(drvdata->hid_dev->name, "Corsair ", 8)) 287 + val->strval = drvdata->hid_dev->name + 8; 288 + else 289 + val->strval = drvdata->hid_dev->name; 290 + break; 291 + case POWER_SUPPLY_PROP_MANUFACTURER: 292 + val->strval = "Corsair"; 293 + break; 294 + case POWER_SUPPLY_PROP_STATUS: 295 + val->intval = drvdata->battery_data.status; 296 + break; 297 + case POWER_SUPPLY_PROP_PRESENT: 298 + val->intval = drvdata->battery_data.present; 299 + break; 300 + case POWER_SUPPLY_PROP_CAPACITY: 301 + val->intval = drvdata->battery_data.capacity; 302 + break; 303 + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 304 + val->intval = drvdata->battery_data.capacity_level; 305 + break; 306 + default: 307 + return -EINVAL; 308 + } 309 + 310 + return 0; 311 + } 312 + 313 + static ssize_t microphone_up_show(struct device *dev, 314 + struct device_attribute *attr, char *buf) 315 + { 316 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 317 + 318 + if (!drvdata->connected) 319 + return -ENODEV; 320 + 321 + return sysfs_emit(buf, "%d\n", drvdata->mic_up); 322 + } 323 + 324 + static ssize_t fw_version_receiver_show(struct device *dev, 325 + struct device_attribute *attr, 326 + char *buf) 327 + { 328 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 329 + 330 + if (drvdata->fw_receiver_major == 0 && drvdata->fw_receiver_minor == 0) 331 + return -ENODATA; 332 + 333 + return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_receiver_major, 334 + drvdata->fw_receiver_minor); 335 + } 336 + 337 + 338 + static ssize_t fw_version_headset_show(struct device *dev, 339 + struct device_attribute *attr, 340 + char *buf) 341 + { 342 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 343 + 344 + if (drvdata->fw_headset_major == 0 && drvdata->fw_headset_minor == 0) 345 + return -ENODATA; 346 + 347 + return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_headset_major, 348 + drvdata->fw_headset_minor); 349 + } 350 + 351 + static ssize_t sidetone_max_show(struct device *dev, 352 + struct device_attribute *attr, 353 + char *buf) 354 + { 355 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 356 + 357 + return sysfs_emit(buf, "%d\n", drvdata->sidetone_max); 358 + } 359 + 360 + /* 361 + * Functions to send data to headset 362 + */ 363 + 364 + static ssize_t send_alert_store(struct device *dev, 365 + struct device_attribute *attr, 366 + const char *buf, size_t count) 367 + { 368 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 369 + struct hid_device *hid_dev = drvdata->hid_dev; 370 + unsigned char alert_id; 371 + unsigned char *send_buf __free(kfree) = NULL; 372 + int ret; 373 + 374 + if (!drvdata->connected || drvdata->is_wired) 375 + return -ENODEV; 376 + 377 + /* Only accept 0 or 1 for alert ID */ 378 + if (kstrtou8(buf, 10, &alert_id) || alert_id >= 2) 379 + return -EINVAL; 380 + 381 + send_buf = kmalloc(3, GFP_KERNEL); 382 + if (!send_buf) 383 + return -ENOMEM; 384 + 385 + /* Packet format to send alert with ID alert_id */ 386 + send_buf[0] = CORSAIR_VOID_NOTIF_REQUEST_ID; 387 + send_buf[1] = 0x02; 388 + send_buf[2] = alert_id; 389 + 390 + ret = hid_hw_raw_request(hid_dev, CORSAIR_VOID_NOTIF_REQUEST_ID, 391 + send_buf, 3, HID_OUTPUT_REPORT, 392 + HID_REQ_SET_REPORT); 393 + if (ret < 0) 394 + hid_warn(hid_dev, "failed to send alert request (reason: %d)", 395 + ret); 396 + else 397 + ret = count; 398 + 399 + return ret; 400 + } 401 + 402 + static int corsair_void_set_sidetone_wired(struct device *dev, const char *buf, 403 + unsigned int sidetone) 404 + { 405 + struct usb_interface *usb_if = to_usb_interface(dev->parent); 406 + struct usb_device *usb_dev = interface_to_usbdev(usb_if); 407 + 408 + /* Packet format to set sidetone for wired headsets */ 409 + __le16 sidetone_le = cpu_to_le16(sidetone); 410 + 411 + return usb_control_msg_send(usb_dev, 0, 412 + CORSAIR_VOID_USB_SIDETONE_REQUEST, 413 + CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE, 414 + CORSAIR_VOID_USB_SIDETONE_VALUE, 415 + CORSAIR_VOID_USB_SIDETONE_INDEX, 416 + &sidetone_le, 2, USB_CTRL_SET_TIMEOUT, 417 + GFP_KERNEL); 418 + } 419 + 420 + static int corsair_void_set_sidetone_wireless(struct device *dev, 421 + const char *buf, 422 + unsigned char sidetone) 423 + { 424 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 425 + struct hid_device *hid_dev = drvdata->hid_dev; 426 + unsigned char *send_buf __free(kfree) = NULL; 427 + 428 + send_buf = kmalloc(12, GFP_KERNEL); 429 + if (!send_buf) 430 + return -ENOMEM; 431 + 432 + /* Packet format to set sidetone for wireless headsets */ 433 + send_buf[0] = CORSAIR_VOID_SIDETONE_REQUEST_ID; 434 + send_buf[1] = 0x0B; 435 + send_buf[2] = 0x00; 436 + send_buf[3] = 0xFF; 437 + send_buf[4] = 0x04; 438 + send_buf[5] = 0x0E; 439 + send_buf[6] = 0xFF; 440 + send_buf[7] = 0x05; 441 + send_buf[8] = 0x01; 442 + send_buf[9] = 0x04; 443 + send_buf[10] = 0x00; 444 + send_buf[11] = sidetone + 200; 445 + 446 + return hid_hw_raw_request(hid_dev, CORSAIR_VOID_SIDETONE_REQUEST_ID, 447 + send_buf, 12, HID_FEATURE_REPORT, 448 + HID_REQ_SET_REPORT); 449 + } 450 + 451 + static ssize_t set_sidetone_store(struct device *dev, 452 + struct device_attribute *attr, 453 + const char *buf, size_t count) 454 + { 455 + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); 456 + struct hid_device *hid_dev = drvdata->hid_dev; 457 + unsigned int sidetone; 458 + int ret; 459 + 460 + if (!drvdata->connected) 461 + return -ENODEV; 462 + 463 + /* sidetone must be between 0 and drvdata->sidetone_max inclusive */ 464 + if (kstrtouint(buf, 10, &sidetone) || sidetone > drvdata->sidetone_max) 465 + return -EINVAL; 466 + 467 + if (drvdata->is_wired) 468 + ret = corsair_void_set_sidetone_wired(dev, buf, sidetone); 469 + else 470 + ret = corsair_void_set_sidetone_wireless(dev, buf, sidetone); 471 + 472 + if (ret < 0) 473 + hid_warn(hid_dev, "failed to send sidetone (reason: %d)", ret); 474 + else 475 + ret = count; 476 + 477 + return ret; 478 + } 479 + 480 + static int corsair_void_request_status(struct hid_device *hid_dev, int id) 481 + { 482 + unsigned char *send_buf __free(kfree) = NULL; 483 + 484 + send_buf = kmalloc(2, GFP_KERNEL); 485 + if (!send_buf) 486 + return -ENOMEM; 487 + 488 + /* Packet format to request data item (status / firmware) refresh */ 489 + send_buf[0] = CORSAIR_VOID_STATUS_REQUEST_ID; 490 + send_buf[1] = id; 491 + 492 + /* Send request for data refresh */ 493 + return hid_hw_raw_request(hid_dev, CORSAIR_VOID_STATUS_REQUEST_ID, 494 + send_buf, 2, HID_OUTPUT_REPORT, 495 + HID_REQ_SET_REPORT); 496 + } 497 + 498 + /* 499 + * Headset connect / disconnect handlers and work handlers 500 + */ 501 + 502 + static void corsair_void_status_work_handler(struct work_struct *work) 503 + { 504 + struct corsair_void_drvdata *drvdata; 505 + struct delayed_work *delayed_work; 506 + int battery_ret; 507 + 508 + delayed_work = container_of(work, struct delayed_work, work); 509 + drvdata = container_of(delayed_work, struct corsair_void_drvdata, 510 + delayed_status_work); 511 + 512 + battery_ret = corsair_void_request_status(drvdata->hid_dev, 513 + CORSAIR_VOID_STATUS_REPORT_ID); 514 + if (battery_ret < 0) { 515 + hid_warn(drvdata->hid_dev, 516 + "failed to request battery (reason: %d)", battery_ret); 517 + } 518 + } 519 + 520 + static void corsair_void_firmware_work_handler(struct work_struct *work) 521 + { 522 + struct corsair_void_drvdata *drvdata; 523 + struct delayed_work *delayed_work; 524 + int firmware_ret; 525 + 526 + delayed_work = container_of(work, struct delayed_work, work); 527 + drvdata = container_of(delayed_work, struct corsair_void_drvdata, 528 + delayed_firmware_work); 529 + 530 + firmware_ret = corsair_void_request_status(drvdata->hid_dev, 531 + CORSAIR_VOID_FIRMWARE_REPORT_ID); 532 + if (firmware_ret < 0) { 533 + hid_warn(drvdata->hid_dev, 534 + "failed to request firmware (reason: %d)", firmware_ret); 535 + } 536 + 537 + } 538 + 539 + static void corsair_void_battery_remove_work_handler(struct work_struct *work) 540 + { 541 + struct corsair_void_drvdata *drvdata; 542 + 543 + drvdata = container_of(work, struct corsair_void_drvdata, 544 + battery_remove_work); 545 + scoped_guard(mutex, &drvdata->battery_mutex) { 546 + if (drvdata->battery) { 547 + power_supply_unregister(drvdata->battery); 548 + drvdata->battery = NULL; 549 + } 550 + } 551 + } 552 + 553 + static void corsair_void_battery_add_work_handler(struct work_struct *work) 554 + { 555 + struct corsair_void_drvdata *drvdata; 556 + struct power_supply_config psy_cfg; 557 + struct power_supply *new_supply; 558 + 559 + drvdata = container_of(work, struct corsair_void_drvdata, 560 + battery_add_work); 561 + guard(mutex)(&drvdata->battery_mutex); 562 + if (drvdata->battery) 563 + return; 564 + 565 + psy_cfg.drv_data = drvdata; 566 + new_supply = power_supply_register(drvdata->dev, 567 + &drvdata->battery_desc, 568 + &psy_cfg); 569 + 570 + if (IS_ERR(new_supply)) { 571 + hid_err(drvdata->hid_dev, 572 + "failed to register battery '%s' (reason: %ld)\n", 573 + drvdata->battery_desc.name, 574 + PTR_ERR(new_supply)); 575 + return; 576 + } 577 + 578 + if (power_supply_powers(new_supply, drvdata->dev)) { 579 + power_supply_unregister(new_supply); 580 + return; 581 + } 582 + 583 + drvdata->battery = new_supply; 584 + } 585 + 586 + static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata) 587 + { 588 + schedule_work(&drvdata->battery_add_work); 589 + schedule_delayed_work(&drvdata->delayed_firmware_work, 590 + msecs_to_jiffies(100)); 591 + } 592 + 593 + static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata) 594 + { 595 + schedule_work(&drvdata->battery_remove_work); 596 + 597 + corsair_void_set_unknown_wireless_data(drvdata); 598 + corsair_void_set_unknown_batt(drvdata); 599 + } 600 + 601 + /* 602 + * Driver setup, probing and HID event handling 603 + */ 604 + 605 + static DEVICE_ATTR_RO(fw_version_receiver); 606 + static DEVICE_ATTR_RO(fw_version_headset); 607 + static DEVICE_ATTR_RO(microphone_up); 608 + static DEVICE_ATTR_RO(sidetone_max); 609 + 610 + static DEVICE_ATTR_WO(send_alert); 611 + static DEVICE_ATTR_WO(set_sidetone); 612 + 613 + static struct attribute *corsair_void_attrs[] = { 614 + &dev_attr_fw_version_receiver.attr, 615 + &dev_attr_fw_version_headset.attr, 616 + &dev_attr_microphone_up.attr, 617 + &dev_attr_send_alert.attr, 618 + &dev_attr_set_sidetone.attr, 619 + &dev_attr_sidetone_max.attr, 620 + NULL, 621 + }; 622 + 623 + static const struct attribute_group corsair_void_attr_group = { 624 + .attrs = corsair_void_attrs, 625 + }; 626 + 627 + static int corsair_void_probe(struct hid_device *hid_dev, 628 + const struct hid_device_id *hid_id) 629 + { 630 + int ret; 631 + struct corsair_void_drvdata *drvdata; 632 + char *name; 633 + 634 + if (!hid_is_usb(hid_dev)) 635 + return -EINVAL; 636 + 637 + drvdata = devm_kzalloc(&hid_dev->dev, sizeof(*drvdata), 638 + GFP_KERNEL); 639 + if (!drvdata) 640 + return -ENOMEM; 641 + 642 + hid_set_drvdata(hid_dev, drvdata); 643 + dev_set_drvdata(&hid_dev->dev, drvdata); 644 + 645 + drvdata->dev = &hid_dev->dev; 646 + drvdata->hid_dev = hid_dev; 647 + drvdata->is_wired = hid_id->driver_data == CORSAIR_VOID_WIRED; 648 + 649 + drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRELESS; 650 + if (drvdata->is_wired) 651 + drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRED; 652 + 653 + /* Set initial values for no wireless headset attached */ 654 + /* If a headset is attached, it'll be prompted later */ 655 + corsair_void_set_unknown_wireless_data(drvdata); 656 + corsair_void_set_unknown_batt(drvdata); 657 + 658 + /* Receiver version won't be reset after init */ 659 + /* Headset version already set via set_unknown_wireless_data */ 660 + drvdata->fw_receiver_major = 0; 661 + drvdata->fw_receiver_minor = 0; 662 + 663 + ret = hid_parse(hid_dev); 664 + if (ret) { 665 + hid_err(hid_dev, "parse failed (reason: %d)\n", ret); 666 + return ret; 667 + } 668 + 669 + name = devm_kasprintf(drvdata->dev, GFP_KERNEL, 670 + "corsair-void-%d-battery", hid_dev->id); 671 + if (!name) 672 + return -ENOMEM; 673 + 674 + drvdata->battery_desc.name = name; 675 + drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 676 + drvdata->battery_desc.properties = corsair_void_battery_props; 677 + drvdata->battery_desc.num_properties = ARRAY_SIZE(corsair_void_battery_props); 678 + drvdata->battery_desc.get_property = corsair_void_battery_get_property; 679 + 680 + drvdata->battery = NULL; 681 + INIT_WORK(&drvdata->battery_remove_work, 682 + corsair_void_battery_remove_work_handler); 683 + INIT_WORK(&drvdata->battery_add_work, 684 + corsair_void_battery_add_work_handler); 685 + ret = devm_mutex_init(drvdata->dev, &drvdata->battery_mutex); 686 + if (ret) 687 + return ret; 688 + 689 + ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 690 + if (ret) 691 + return ret; 692 + 693 + /* Any failures after here will need to call hid_hw_stop */ 694 + ret = hid_hw_start(hid_dev, HID_CONNECT_DEFAULT); 695 + if (ret) { 696 + hid_err(hid_dev, "hid_hw_start failed (reason: %d)\n", ret); 697 + goto failed_after_sysfs; 698 + } 699 + 700 + /* Refresh battery data, in case wireless headset is already connected */ 701 + INIT_DELAYED_WORK(&drvdata->delayed_status_work, 702 + corsair_void_status_work_handler); 703 + schedule_delayed_work(&drvdata->delayed_status_work, 704 + msecs_to_jiffies(100)); 705 + 706 + /* Refresh firmware versions */ 707 + INIT_DELAYED_WORK(&drvdata->delayed_firmware_work, 708 + corsair_void_firmware_work_handler); 709 + schedule_delayed_work(&drvdata->delayed_firmware_work, 710 + msecs_to_jiffies(100)); 711 + 712 + return 0; 713 + 714 + failed_after_sysfs: 715 + sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 716 + return ret; 717 + } 718 + 719 + static void corsair_void_remove(struct hid_device *hid_dev) 720 + { 721 + struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 722 + 723 + hid_hw_stop(hid_dev); 724 + cancel_work_sync(&drvdata->battery_remove_work); 725 + cancel_work_sync(&drvdata->battery_add_work); 726 + if (drvdata->battery) 727 + power_supply_unregister(drvdata->battery); 728 + 729 + cancel_delayed_work_sync(&drvdata->delayed_firmware_work); 730 + sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); 731 + } 732 + 733 + static int corsair_void_raw_event(struct hid_device *hid_dev, 734 + struct hid_report *hid_report, 735 + u8 *data, int size) 736 + { 737 + struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); 738 + bool was_connected = drvdata->connected; 739 + 740 + /* Description of packets are documented at the top of this file */ 741 + if (hid_report->id == CORSAIR_VOID_STATUS_REPORT_ID) { 742 + drvdata->mic_up = FIELD_GET(CORSAIR_VOID_MIC_MASK, data[2]); 743 + drvdata->connected = (data[3] == CORSAIR_VOID_WIRELESS_CONNECTED) || 744 + drvdata->is_wired; 745 + 746 + corsair_void_process_receiver(drvdata, 747 + FIELD_GET(CORSAIR_VOID_CAPACITY_MASK, data[2]), 748 + data[3], data[4]); 749 + } else if (hid_report->id == CORSAIR_VOID_FIRMWARE_REPORT_ID) { 750 + drvdata->fw_receiver_major = data[1]; 751 + drvdata->fw_receiver_minor = data[2]; 752 + drvdata->fw_headset_major = data[3]; 753 + drvdata->fw_headset_minor = data[4]; 754 + } 755 + 756 + /* Handle wireless headset connect / disconnect */ 757 + if ((was_connected != drvdata->connected) && !drvdata->is_wired) { 758 + if (drvdata->connected) 759 + corsair_void_headset_connected(drvdata); 760 + else 761 + corsair_void_headset_disconnected(drvdata); 762 + } 763 + 764 + return 0; 765 + } 766 + 767 + static const struct hid_device_id corsair_void_devices[] = { 768 + /* Corsair Void Wireless */ 769 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a0c), 770 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a2b), 771 + CORSAIR_VOID_WIRELESS_DEVICE(0x1b23), 772 + CORSAIR_VOID_WIRELESS_DEVICE(0x1b25), 773 + CORSAIR_VOID_WIRELESS_DEVICE(0x1b27), 774 + 775 + /* Corsair Void USB */ 776 + CORSAIR_VOID_WIRED_DEVICE(0x0a0f), 777 + CORSAIR_VOID_WIRED_DEVICE(0x1b1c), 778 + CORSAIR_VOID_WIRED_DEVICE(0x1b29), 779 + CORSAIR_VOID_WIRED_DEVICE(0x1b2a), 780 + 781 + /* Corsair Void Surround */ 782 + CORSAIR_VOID_WIRED_DEVICE(0x0a30), 783 + CORSAIR_VOID_WIRED_DEVICE(0x0a31), 784 + 785 + /* Corsair Void Pro Wireless */ 786 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a14), 787 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a16), 788 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a1a), 789 + 790 + /* Corsair Void Pro USB */ 791 + CORSAIR_VOID_WIRED_DEVICE(0x0a17), 792 + CORSAIR_VOID_WIRED_DEVICE(0x0a1d), 793 + 794 + /* Corsair Void Pro Surround */ 795 + CORSAIR_VOID_WIRED_DEVICE(0x0a18), 796 + CORSAIR_VOID_WIRED_DEVICE(0x0a1e), 797 + CORSAIR_VOID_WIRED_DEVICE(0x0a1f), 798 + 799 + /* Corsair Void Elite Wireless */ 800 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a51), 801 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a55), 802 + CORSAIR_VOID_WIRELESS_DEVICE(0x0a75), 803 + 804 + /* Corsair Void Elite USB */ 805 + CORSAIR_VOID_WIRED_DEVICE(0x0a52), 806 + CORSAIR_VOID_WIRED_DEVICE(0x0a56), 807 + 808 + /* Corsair Void Elite Surround */ 809 + CORSAIR_VOID_WIRED_DEVICE(0x0a53), 810 + CORSAIR_VOID_WIRED_DEVICE(0x0a57), 811 + 812 + {} 813 + }; 814 + 815 + MODULE_DEVICE_TABLE(hid, corsair_void_devices); 816 + 817 + static struct hid_driver corsair_void_driver = { 818 + .name = "hid-corsair-void", 819 + .id_table = corsair_void_devices, 820 + .probe = corsair_void_probe, 821 + .remove = corsair_void_remove, 822 + .raw_event = corsair_void_raw_event, 823 + }; 824 + 825 + module_hid_driver(corsair_void_driver); 826 + 827 + MODULE_LICENSE("GPL"); 828 + MODULE_AUTHOR("Stuart Hayhurst <stuart.a.hayhurst@gmail.com>"); 829 + MODULE_DESCRIPTION("HID driver for Corsair Void headsets");
+2 -1
drivers/hid/hid-cp2112.c
··· 852 852 { 853 853 int ret; 854 854 855 - BUG_ON(cfg->report != CP2112_USB_CONFIG); 855 + if (WARN_ON(cfg->report != CP2112_USB_CONFIG)) 856 + return -EINVAL; 856 857 857 858 ret = cp2112_hid_output(hdev, (u8 *)cfg, sizeof(*cfg), 858 859 HID_FEATURE_REPORT);
+4 -5
drivers/hid/hid-debug.c
··· 3309 3309 [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", 3310 3310 [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", 3311 3311 [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", 3312 - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", 3312 + [KEY_ANGLE] = "Angle", 3313 3313 [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", 3314 - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", 3314 + [KEY_PC] = "PC", 3315 3315 [KEY_TV] = "TV", [KEY_TV2] = "TV2", 3316 3316 [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", 3317 3317 [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", ··· 3409 3409 [BTN_TRIGGER_HAPPY35] = "TriggerHappy35", [BTN_TRIGGER_HAPPY36] = "TriggerHappy36", 3410 3410 [BTN_TRIGGER_HAPPY37] = "TriggerHappy37", [BTN_TRIGGER_HAPPY38] = "TriggerHappy38", 3411 3411 [BTN_TRIGGER_HAPPY39] = "TriggerHappy39", [BTN_TRIGGER_HAPPY40] = "TriggerHappy40", 3412 - [BTN_DIGI] = "Digi", [BTN_STYLUS3] = "Stylus3", 3413 - [BTN_TOOL_QUINTTAP] = "ToolQuintTap", [BTN_WHEEL] = "Wheel", 3412 + [BTN_STYLUS3] = "Stylus3", [BTN_TOOL_QUINTTAP] = "ToolQuintTap", 3414 3413 [KEY_10CHANNELSDOWN] = "10ChannelsDown", 3415 3414 [KEY_10CHANNELSUP] = "10ChannelsUp", 3416 3415 [KEY_3D_MODE] = "3DMode", [KEY_ADDRESSBOOK] = "Addressbook", ··· 3439 3440 [KEY_FN_RIGHT_SHIFT] = "FnRightShift", [KEY_FRAMEBACK] = "FrameBack", 3440 3441 [KEY_FRAMEFORWARD] = "FrameForward", [KEY_FULL_SCREEN] = "FullScreen", 3441 3442 [KEY_GAMES] = "Games", [KEY_GRAPHICSEDITOR] = "GraphicsEditor", 3442 - [KEY_HANGEUL] = "HanGeul", [KEY_HANGUP_PHONE] = "HangUpPhone", 3443 + [KEY_HANGUP_PHONE] = "HangUpPhone", 3443 3444 [KEY_IMAGES] = "Images", [KEY_KBD_LCD_MENU1] = "KbdLcdMenu1", 3444 3445 [KEY_KBD_LCD_MENU2] = "KbdLcdMenu2", [KEY_KBD_LCD_MENU3] = "KbdLcdMenu3", 3445 3446 [KEY_KBD_LCD_MENU4] = "KbdLcdMenu4", [KEY_KBD_LCD_MENU5] = "KbdLcdMenu5",
+3
drivers/hid/hid-generic.c
··· 40 40 if (ignore_special_driver) 41 41 return true; 42 42 43 + if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER) 44 + return true; 45 + 43 46 if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER) 44 47 return false; 45 48
+22 -13
drivers/hid/hid-goodix-spi.c
··· 19 19 #define GOODIX_HID_DESC_ADDR 0x1058C 20 20 #define GOODIX_HID_REPORT_DESC_ADDR 0x105AA 21 21 #define GOODIX_HID_SIGN_ADDR 0x10D32 22 + #define GOODIX_HID_CMD_ADDR 0x10364 23 + #define GOODIX_HID_REPORT_ADDR 0x22C8C 22 24 23 25 #define GOODIX_HID_GET_REPORT_CMD 0x02 24 26 #define GOODIX_HID_SET_REPORT_CMD 0x03 ··· 350 348 * - byte 0: Ack flag, value of 1 for data ready 351 349 * - bytes 1-2: Response data length 352 350 */ 353 - error = goodix_spi_read(ts, ts->hid_report_addr, 351 + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR, 354 352 &hdr, sizeof(hdr)); 355 353 if (!error && (hdr.flag & GOODIX_HID_ACK_READY_FLAG)) { 356 354 len = le16_to_cpu(hdr.size); ··· 358 356 dev_err(ts->dev, "hrd.size too short: %d", len); 359 357 return -EINVAL; 360 358 } 361 - *resp_len = len; 359 + *resp_len = len - GOODIX_HID_PKG_LEN_SIZE; 362 360 return 0; 363 361 } 364 362 ··· 433 431 tx_len += args_len; 434 432 435 433 /* Step1: write report request info */ 436 - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); 434 + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); 437 435 if (error) { 438 436 dev_err(ts->dev, "failed send read feature cmd, %d", error); 439 437 return error; ··· 448 446 if (error) 449 447 return error; 450 448 451 - len = min(len, response_data_len - GOODIX_HID_PKG_LEN_SIZE); 449 + /* Empty reprot response */ 450 + if (!response_data_len) 451 + return 0; 452 + len = min(len, response_data_len); 452 453 /* Step3: read response data(skip 2bytes of hid pkg length) */ 453 - error = goodix_spi_read(ts, ts->hid_report_addr + 454 + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR + 454 455 GOODIX_HID_ACK_HEADER_SIZE + 455 456 GOODIX_HID_PKG_LEN_SIZE, buf, len); 456 457 if (error) { ··· 523 518 memcpy(tmp_buf + tx_len, buf, len); 524 519 tx_len += len; 525 520 526 - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); 521 + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); 527 522 if (error) { 528 523 dev_err(ts->dev, "failed send report: %*ph", tx_len, tmp_buf); 529 524 return error; ··· 702 697 return dev_err_probe(dev, PTR_ERR(ts->reset_gpio), 703 698 "failed to request reset gpio\n"); 704 699 705 - error = device_property_read_u32(dev, "goodix,hid-report-addr", 706 - &ts->hid_report_addr); 707 - if (error) 708 - return dev_err_probe(dev, error, 709 - "failed get hid report addr\n"); 710 - 700 + ts->hid_report_addr = GOODIX_HID_REPORT_ADDR; 711 701 error = goodix_dev_confirm(ts); 712 702 if (error) 713 703 return error; ··· 749 749 power_control_cmd[5] = power_state; 750 750 751 751 guard(mutex)(&ts->hid_request_lock); 752 - error = goodix_spi_write(ts, ts->hid_report_addr, power_control_cmd, 752 + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, power_control_cmd, 753 753 sizeof(power_control_cmd)); 754 754 if (error) { 755 755 dev_err(ts->dev, "failed set power mode: %s", ··· 786 786 MODULE_DEVICE_TABLE(acpi, goodix_spi_acpi_match); 787 787 #endif 788 788 789 + #ifdef CONFIG_OF 790 + static const struct of_device_id goodix_spi_of_match[] = { 791 + { .compatible = "goodix,gt7986u-spifw", }, 792 + { } 793 + }; 794 + MODULE_DEVICE_TABLE(of, goodix_spi_of_match); 795 + #endif 796 + 789 797 static const struct spi_device_id goodix_spi_ids[] = { 790 798 { "gt7986u" }, 791 799 { }, ··· 804 796 .driver = { 805 797 .name = "goodix-spi-hid", 806 798 .acpi_match_table = ACPI_PTR(goodix_spi_acpi_match), 799 + .of_match_table = of_match_ptr(goodix_spi_of_match), 807 800 .pm = pm_sleep_ptr(&goodix_spi_pm_ops), 808 801 }, 809 802 .probe = goodix_spi_probe,
+41 -17
drivers/hid/hid-hyperv.c
··· 422 422 return 0; 423 423 } 424 424 425 + static int mousevsc_hid_probe(struct hid_device *hid_dev, const struct hid_device_id *id) 426 + { 427 + int ret; 428 + 429 + ret = hid_parse(hid_dev); 430 + if (ret) { 431 + hid_err(hid_dev, "parse failed\n"); 432 + return ret; 433 + } 434 + 435 + ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); 436 + if (ret) { 437 + hid_err(hid_dev, "hw start failed\n"); 438 + return ret; 439 + } 440 + 441 + return 0; 442 + } 443 + 425 444 static const struct hid_ll_driver mousevsc_ll_driver = { 426 445 .parse = mousevsc_hid_parse, 427 446 .open = mousevsc_hid_open, ··· 450 431 .raw_request = mousevsc_hid_raw_request, 451 432 }; 452 433 453 - static struct hid_driver mousevsc_hid_driver; 434 + static const struct hid_device_id mousevsc_devices[] = { 435 + { HID_DEVICE(BUS_VIRTUAL, HID_GROUP_ANY, 0x045E, 0x0621) }, 436 + { } 437 + }; 438 + 439 + static struct hid_driver mousevsc_hid_driver = { 440 + .name = "hid-hyperv", 441 + .id_table = mousevsc_devices, 442 + .probe = mousevsc_hid_probe, 443 + }; 454 444 455 445 static int mousevsc_probe(struct hv_device *device, 456 446 const struct hv_vmbus_device_id *dev_id) ··· 501 473 } 502 474 503 475 hid_dev->ll_driver = &mousevsc_ll_driver; 504 - hid_dev->driver = &mousevsc_hid_driver; 505 476 hid_dev->bus = BUS_VIRTUAL; 506 477 hid_dev->vendor = input_dev->hid_dev_info.vendor; 507 478 hid_dev->product = input_dev->hid_dev_info.product; ··· 514 487 ret = hid_add_device(hid_dev); 515 488 if (ret) 516 489 goto probe_err2; 517 - 518 - 519 - ret = hid_parse(hid_dev); 520 - if (ret) { 521 - hid_err(hid_dev, "parse failed\n"); 522 - goto probe_err2; 523 - } 524 - 525 - ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); 526 - 527 - if (ret) { 528 - hid_err(hid_dev, "hw start failed\n"); 529 - goto probe_err2; 530 - } 531 490 532 491 device_init_wakeup(&device->device, true); 533 492 ··· 592 579 593 580 static int __init mousevsc_init(void) 594 581 { 595 - return vmbus_driver_register(&mousevsc_drv); 582 + int ret; 583 + 584 + ret = hid_register_driver(&mousevsc_hid_driver); 585 + if (ret) 586 + return ret; 587 + 588 + ret = vmbus_driver_register(&mousevsc_drv); 589 + if (ret) 590 + hid_unregister_driver(&mousevsc_hid_driver); 591 + 592 + return ret; 596 593 } 597 594 598 595 static void __exit mousevsc_exit(void) 599 596 { 600 597 vmbus_driver_unregister(&mousevsc_drv); 598 + hid_unregister_driver(&mousevsc_hid_driver); 601 599 } 602 600 603 601 MODULE_LICENSE("GPL");
+5
drivers/hid/hid-ids.h
··· 94 94 #define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269 95 95 #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e 96 96 #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265 97 + #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC 0x0324 97 98 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e 98 99 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f 99 100 #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 ··· 735 734 #define USB_DEVICE_ID_KYE_EASYPEN_M406XE 0x5019 736 735 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501A 737 736 #define USB_DEVICE_ID_KYE_PENSKETCH_T609A 0x501B 737 + 738 + #define USB_VENDOR_ID_KYSONA 0x3554 739 + #define USB_DEVICE_ID_KYSONA_M600_DONGLE 0xF57C 740 + #define USB_DEVICE_ID_KYSONA_M600_WIRED 0xF57D 738 741 739 742 #define USB_VENDOR_ID_LABTEC 0x1020 740 743 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+248
drivers/hid/hid-kysona.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * USB HID driver for Kysona 4 + * Kysona M600 mice. 5 + * 6 + * Copyright (c) 2024 Lode Willems <me@lodewillems.com> 7 + */ 8 + 9 + #include <linux/device.h> 10 + #include <linux/hid.h> 11 + #include <linux/usb.h> 12 + 13 + #include "hid-ids.h" 14 + 15 + #define BATTERY_TIMEOUT_MS 5000 16 + 17 + #define BATTERY_REPORT_ID 4 18 + 19 + struct kysona_drvdata { 20 + struct hid_device *hdev; 21 + bool online; 22 + 23 + struct power_supply_desc battery_desc; 24 + struct power_supply *battery; 25 + u8 battery_capacity; 26 + bool battery_charging; 27 + u16 battery_voltage; 28 + struct delayed_work battery_work; 29 + }; 30 + 31 + static enum power_supply_property kysona_battery_props[] = { 32 + POWER_SUPPLY_PROP_STATUS, 33 + POWER_SUPPLY_PROP_PRESENT, 34 + POWER_SUPPLY_PROP_CAPACITY, 35 + POWER_SUPPLY_PROP_SCOPE, 36 + POWER_SUPPLY_PROP_MODEL_NAME, 37 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 38 + POWER_SUPPLY_PROP_ONLINE 39 + }; 40 + 41 + static int kysona_battery_get_property(struct power_supply *psy, 42 + enum power_supply_property psp, 43 + union power_supply_propval *val) 44 + { 45 + struct kysona_drvdata *drv_data = power_supply_get_drvdata(psy); 46 + int ret = 0; 47 + 48 + switch (psp) { 49 + case POWER_SUPPLY_PROP_PRESENT: 50 + val->intval = 1; 51 + break; 52 + case POWER_SUPPLY_PROP_ONLINE: 53 + val->intval = drv_data->online; 54 + break; 55 + case POWER_SUPPLY_PROP_STATUS: 56 + if (drv_data->online) 57 + val->intval = drv_data->battery_charging ? 58 + POWER_SUPPLY_STATUS_CHARGING : 59 + POWER_SUPPLY_STATUS_DISCHARGING; 60 + else 61 + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 62 + break; 63 + case POWER_SUPPLY_PROP_SCOPE: 64 + val->intval = POWER_SUPPLY_SCOPE_DEVICE; 65 + break; 66 + case POWER_SUPPLY_PROP_CAPACITY: 67 + val->intval = drv_data->battery_capacity; 68 + break; 69 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 70 + /* hardware reports voltage in mV. sysfs expects uV */ 71 + val->intval = drv_data->battery_voltage * 1000; 72 + break; 73 + case POWER_SUPPLY_PROP_MODEL_NAME: 74 + val->strval = drv_data->hdev->name; 75 + break; 76 + default: 77 + ret = -EINVAL; 78 + break; 79 + } 80 + return ret; 81 + } 82 + 83 + static const char kysona_battery_request[] = { 84 + 0x08, BATTERY_REPORT_ID, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49 86 + }; 87 + 88 + static int kysona_m600_fetch_battery(struct hid_device *hdev) 89 + { 90 + u8 *write_buf; 91 + int ret; 92 + 93 + /* Request battery information */ 94 + write_buf = kmemdup(kysona_battery_request, sizeof(kysona_battery_request), GFP_KERNEL); 95 + if (!write_buf) 96 + return -ENOMEM; 97 + 98 + ret = hid_hw_raw_request(hdev, kysona_battery_request[0], 99 + write_buf, sizeof(kysona_battery_request), 100 + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 101 + if (ret < (int)sizeof(kysona_battery_request)) { 102 + hid_err(hdev, "hid_hw_raw_request() failed with %d\n", ret); 103 + ret = -ENODATA; 104 + } 105 + kfree(write_buf); 106 + return ret; 107 + } 108 + 109 + static void kysona_fetch_battery(struct hid_device *hdev) 110 + { 111 + int ret = kysona_m600_fetch_battery(hdev); 112 + 113 + if (ret < 0) 114 + hid_dbg(hdev, 115 + "Battery query failed (err: %d)\n", ret); 116 + } 117 + 118 + static void kysona_battery_timer_tick(struct work_struct *work) 119 + { 120 + struct kysona_drvdata *drv_data = container_of(work, 121 + struct kysona_drvdata, battery_work.work); 122 + struct hid_device *hdev = drv_data->hdev; 123 + 124 + kysona_fetch_battery(hdev); 125 + schedule_delayed_work(&drv_data->battery_work, 126 + msecs_to_jiffies(BATTERY_TIMEOUT_MS)); 127 + } 128 + 129 + static int kysona_battery_probe(struct hid_device *hdev) 130 + { 131 + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); 132 + struct power_supply_config pscfg = { .drv_data = drv_data }; 133 + int ret = 0; 134 + 135 + drv_data->online = false; 136 + drv_data->battery_capacity = 100; 137 + drv_data->battery_voltage = 4200; 138 + 139 + drv_data->battery_desc.properties = kysona_battery_props; 140 + drv_data->battery_desc.num_properties = ARRAY_SIZE(kysona_battery_props); 141 + drv_data->battery_desc.get_property = kysona_battery_get_property; 142 + drv_data->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; 143 + drv_data->battery_desc.use_for_apm = 0; 144 + drv_data->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, 145 + "kysona-%s-battery", 146 + strlen(hdev->uniq) ? 147 + hdev->uniq : dev_name(&hdev->dev)); 148 + if (!drv_data->battery_desc.name) 149 + return -ENOMEM; 150 + 151 + drv_data->battery = devm_power_supply_register(&hdev->dev, 152 + &drv_data->battery_desc, &pscfg); 153 + if (IS_ERR(drv_data->battery)) { 154 + ret = PTR_ERR(drv_data->battery); 155 + drv_data->battery = NULL; 156 + hid_err(hdev, "Unable to register battery device\n"); 157 + return ret; 158 + } 159 + 160 + power_supply_powers(drv_data->battery, &hdev->dev); 161 + 162 + INIT_DELAYED_WORK(&drv_data->battery_work, kysona_battery_timer_tick); 163 + kysona_fetch_battery(hdev); 164 + schedule_delayed_work(&drv_data->battery_work, 165 + msecs_to_jiffies(BATTERY_TIMEOUT_MS)); 166 + 167 + return ret; 168 + } 169 + 170 + static int kysona_probe(struct hid_device *hdev, const struct hid_device_id *id) 171 + { 172 + int ret; 173 + struct kysona_drvdata *drv_data; 174 + struct usb_interface *usbif; 175 + 176 + if (!hid_is_usb(hdev)) 177 + return -EINVAL; 178 + 179 + usbif = to_usb_interface(hdev->dev.parent); 180 + 181 + drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL); 182 + if (!drv_data) 183 + return -ENOMEM; 184 + 185 + hid_set_drvdata(hdev, drv_data); 186 + drv_data->hdev = hdev; 187 + 188 + ret = hid_parse(hdev); 189 + if (ret) 190 + return ret; 191 + 192 + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 193 + if (ret) 194 + return ret; 195 + 196 + if (usbif->cur_altsetting->desc.bInterfaceNumber == 1) { 197 + if (kysona_battery_probe(hdev) < 0) 198 + hid_err(hdev, "Kysona hid battery_probe failed: %d\n", ret); 199 + } 200 + 201 + return 0; 202 + } 203 + 204 + static int kysona_raw_event(struct hid_device *hdev, 205 + struct hid_report *report, u8 *data, int size) 206 + { 207 + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); 208 + 209 + if (drv_data->battery && size == sizeof(kysona_battery_request) && 210 + data[0] == 8 && data[1] == BATTERY_REPORT_ID) { 211 + drv_data->battery_capacity = data[6]; 212 + drv_data->battery_charging = data[7]; 213 + drv_data->battery_voltage = (data[8] << 8) | data[9]; 214 + drv_data->online = true; 215 + } 216 + 217 + return 0; 218 + } 219 + 220 + static void kysona_remove(struct hid_device *hdev) 221 + { 222 + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); 223 + 224 + if (drv_data->battery) 225 + cancel_delayed_work_sync(&drv_data->battery_work); 226 + 227 + hid_hw_stop(hdev); 228 + } 229 + 230 + static const struct hid_device_id kysona_devices[] = { 231 + { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_DONGLE) }, 232 + { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_WIRED) }, 233 + { } 234 + }; 235 + MODULE_DEVICE_TABLE(hid, kysona_devices); 236 + 237 + static struct hid_driver kysona_driver = { 238 + .name = "kysona", 239 + .id_table = kysona_devices, 240 + .probe = kysona_probe, 241 + .raw_event = kysona_raw_event, 242 + .remove = kysona_remove 243 + }; 244 + module_hid_driver(kysona_driver); 245 + 246 + MODULE_LICENSE("GPL"); 247 + MODULE_DESCRIPTION("HID driver for Kysona devices"); 248 + MODULE_AUTHOR("Lode Willems <me@lodewillems.com>");
+2 -1
drivers/hid/hid-lg4ff.c
··· 1350 1350 1351 1351 /* Initialize device properties */ 1352 1352 if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { 1353 - BUG_ON(mmode_idx == -1); 1353 + if (WARN_ON(mmode_idx == -1)) 1354 + return -EINVAL; 1354 1355 mmode_wheel = &lg4ff_multimode_wheels[mmode_idx]; 1355 1356 } 1356 1357 lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, real_product_id);
+23 -51
drivers/hid/hid-logitech-hidpp.c
··· 928 928 #define CMD_ROOT_GET_PROTOCOL_VERSION 0x10 929 929 930 930 static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature, 931 - u8 *feature_index, u8 *feature_type) 931 + u8 *feature_index) 932 932 { 933 933 struct hidpp_report response; 934 934 int ret; ··· 945 945 return -ENOENT; 946 946 947 947 *feature_index = response.fap.params[0]; 948 - *feature_type = response.fap.params[1]; 949 948 950 949 return ret; 951 950 } ··· 1011 1012 static int hidpp_get_serial(struct hidpp_device *hidpp, u32 *serial) 1012 1013 { 1013 1014 struct hidpp_report response; 1014 - u8 feature_type; 1015 1015 u8 feature_index; 1016 1016 int ret; 1017 1017 1018 1018 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_DEVICE_INFORMATION, 1019 - &feature_index, 1020 - &feature_type); 1019 + &feature_index); 1021 1020 if (ret) 1022 1021 return ret; 1023 1022 ··· 1122 1125 1123 1126 static char *hidpp_get_device_name(struct hidpp_device *hidpp) 1124 1127 { 1125 - u8 feature_type; 1126 1128 u8 feature_index; 1127 1129 u8 __name_length; 1128 1130 char *name; ··· 1129 1133 int ret; 1130 1134 1131 1135 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_GET_DEVICE_NAME_TYPE, 1132 - &feature_index, &feature_type); 1136 + &feature_index); 1133 1137 if (ret) 1134 1138 return NULL; 1135 1139 ··· 1296 1300 1297 1301 static int hidpp20_query_battery_info_1000(struct hidpp_device *hidpp) 1298 1302 { 1299 - u8 feature_type; 1300 1303 int ret; 1301 1304 int status, capacity, next_capacity, level; 1302 1305 1303 1306 if (hidpp->battery.feature_index == 0xff) { 1304 1307 ret = hidpp_root_get_feature(hidpp, 1305 1308 HIDPP_PAGE_BATTERY_LEVEL_STATUS, 1306 - &hidpp->battery.feature_index, 1307 - &feature_type); 1309 + &hidpp->battery.feature_index); 1308 1310 if (ret) 1309 1311 return ret; 1310 1312 } ··· 1483 1489 1484 1490 static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp) 1485 1491 { 1486 - u8 feature_type; 1487 1492 int ret; 1488 1493 int status, voltage, level, charge_type; 1489 1494 1490 1495 if (hidpp->battery.voltage_feature_index == 0xff) { 1491 1496 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_BATTERY_VOLTAGE, 1492 - &hidpp->battery.voltage_feature_index, 1493 - &feature_type); 1497 + &hidpp->battery.voltage_feature_index); 1494 1498 if (ret) 1495 1499 return ret; 1496 1500 } ··· 1684 1692 1685 1693 static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp) 1686 1694 { 1687 - u8 feature_type; 1688 1695 int ret; 1689 1696 u8 state_of_charge; 1690 1697 int status, level; ··· 1691 1700 if (hidpp->battery.feature_index == 0xff) { 1692 1701 ret = hidpp_root_get_feature(hidpp, 1693 1702 HIDPP_PAGE_UNIFIED_BATTERY, 1694 - &hidpp->battery.feature_index, 1695 - &feature_type); 1703 + &hidpp->battery.feature_index); 1696 1704 if (ret) 1697 1705 return ret; 1698 1706 } ··· 1824 1834 1825 1835 static int hidpp_get_wireless_feature_index(struct hidpp_device *hidpp, u8 *feature_index) 1826 1836 { 1827 - u8 feature_type; 1828 - int ret; 1829 - 1830 - ret = hidpp_root_get_feature(hidpp, 1831 - HIDPP_PAGE_WIRELESS_DEVICE_STATUS, 1832 - feature_index, &feature_type); 1833 - 1834 - return ret; 1837 + return hidpp_root_get_feature(hidpp, 1838 + HIDPP_PAGE_WIRELESS_DEVICE_STATUS, 1839 + feature_index); 1835 1840 } 1836 1841 1837 1842 /* -------------------------------------------------------------------------- */ ··· 1937 1952 1938 1953 static int hidpp20_query_adc_measurement_info_1f20(struct hidpp_device *hidpp) 1939 1954 { 1940 - u8 feature_type; 1941 - 1942 1955 if (hidpp->battery.adc_measurement_feature_index == 0xff) { 1943 1956 int ret; 1944 1957 1945 1958 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_ADC_MEASUREMENT, 1946 - &hidpp->battery.adc_measurement_feature_index, 1947 - &feature_type); 1959 + &hidpp->battery.adc_measurement_feature_index); 1948 1960 if (ret) 1949 1961 return ret; 1950 1962 ··· 1996 2014 bool enabled, u8 *multiplier) 1997 2015 { 1998 2016 u8 feature_index; 1999 - u8 feature_type; 2000 2017 int ret; 2001 2018 u8 params[1]; 2002 2019 struct hidpp_report response; 2003 2020 2004 2021 ret = hidpp_root_get_feature(hidpp, 2005 2022 HIDPP_PAGE_HI_RESOLUTION_SCROLLING, 2006 - &feature_index, 2007 - &feature_type); 2023 + &feature_index); 2008 2024 if (ret) 2009 2025 return ret; 2010 2026 ··· 2029 2049 u8 *multiplier) 2030 2050 { 2031 2051 u8 feature_index; 2032 - u8 feature_type; 2033 2052 int ret; 2034 2053 struct hidpp_report response; 2035 2054 2036 2055 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, 2037 - &feature_index, &feature_type); 2056 + &feature_index); 2038 2057 if (ret) 2039 2058 goto return_default; 2040 2059 ··· 2055 2076 bool high_resolution, bool use_hidpp) 2056 2077 { 2057 2078 u8 feature_index; 2058 - u8 feature_type; 2059 2079 int ret; 2060 2080 u8 params[1]; 2061 2081 struct hidpp_report response; 2062 2082 2063 2083 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, 2064 - &feature_index, &feature_type); 2084 + &feature_index); 2065 2085 if (ret) 2066 2086 return ret; 2067 2087 ··· 2089 2111 { 2090 2112 struct hidpp_report response; 2091 2113 u8 params[2] = { 1, 1 }; 2092 - u8 feature_type; 2093 2114 int ret; 2094 2115 2095 2116 if (hidpp->battery.feature_index == 0xff) { 2096 2117 ret = hidpp_root_get_feature(hidpp, 2097 2118 HIDPP_PAGE_SOLAR_KEYBOARD, 2098 - &hidpp->battery.solar_feature_index, 2099 - &feature_type); 2119 + &hidpp->battery.solar_feature_index); 2100 2120 if (ret) 2101 2121 return ret; 2102 2122 } ··· 2498 2522 /* regular effect destroyed */ 2499 2523 data->effect_ids[wd->params[0]-1] = -1; 2500 2524 else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) 2501 - /* autocenter spring destoyed */ 2525 + /* autocenter spring destroyed */ 2502 2526 data->slot_autocenter = 0; 2503 2527 break; 2504 2528 case HIDPP_FF_SET_GLOBAL_GAINS: ··· 3074 3098 { 3075 3099 struct wtp_data *wd = hidpp->private_data; 3076 3100 struct hidpp_touchpad_raw_info raw_info = {0}; 3077 - u8 feature_type; 3078 3101 int ret; 3079 3102 3080 3103 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_TOUCHPAD_RAW_XY, 3081 - &wd->mt_feature_index, &feature_type); 3104 + &wd->mt_feature_index); 3082 3105 if (ret) 3083 3106 /* means that the device is not powered up */ 3084 3107 return ret; ··· 3271 3296 120); 3272 3297 } 3273 3298 3274 - v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); 3299 + v = sign_extend32(hid_field_extract(hdev, data + 3, 0, 12), 11); 3275 3300 input_report_rel(hidpp->input, REL_X, v); 3276 3301 3277 - v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12); 3302 + v = sign_extend32(hid_field_extract(hdev, data + 3, 12, 12), 11); 3278 3303 input_report_rel(hidpp->input, REL_Y, v); 3279 3304 3280 - v = hid_snto32(data[6], 8); 3305 + v = sign_extend32(data[6], 7); 3281 3306 if (v != 0) 3282 3307 hidpp_scroll_counter_handle_scroll(hidpp->input, 3283 3308 &hidpp->vertical_wheel_counter, v); ··· 3337 3362 struct k400_private_data *k400 = hidpp->private_data; 3338 3363 struct hidpp_touchpad_fw_items items = {}; 3339 3364 int ret; 3340 - u8 feature_type; 3341 3365 3342 3366 if (!k400->feature_index) { 3343 3367 ret = hidpp_root_get_feature(hidpp, 3344 3368 HIDPP_PAGE_TOUCHPAD_FW_ITEMS, 3345 - &k400->feature_index, &feature_type); 3369 + &k400->feature_index); 3346 3370 if (ret) 3347 3371 /* means that the device is not powered up */ 3348 3372 return ret; ··· 3413 3439 struct hidpp_ff_private_data *data) 3414 3440 { 3415 3441 struct hidpp_report response; 3416 - u8 feature_type; 3417 3442 int ret; 3418 3443 3419 3444 memset(data, 0, sizeof(*data)); 3420 3445 3421 3446 /* Find feature and store for later use */ 3422 3447 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK, 3423 - &data->feature_index, &feature_type); 3448 + &data->feature_index); 3424 3449 if (ret) 3425 3450 return ret; 3426 3451 ··· 3708 3735 3709 3736 if (hidpp->protocol_major >= 2) { 3710 3737 u8 feature_index; 3711 - u8 feature_type; 3712 3738 3713 3739 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, 3714 - &feature_index, &feature_type); 3740 + &feature_index); 3715 3741 if (!ret) { 3716 3742 hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL; 3717 3743 hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scroll wheel\n"); 3718 3744 return 0; 3719 3745 } 3720 3746 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HI_RESOLUTION_SCROLLING, 3721 - &feature_index, &feature_type); 3747 + &feature_index); 3722 3748 if (!ret) { 3723 3749 hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL; 3724 3750 hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n");
+41 -15
drivers/hid/hid-magicmouse.c
··· 227 227 touch_minor = tdata[4]; 228 228 state = tdata[7] & TOUCH_STATE_MASK; 229 229 down = state != TOUCH_STATE_NONE; 230 - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 230 + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 231 + input->id.product == 232 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 231 233 id = tdata[8] & 0xf; 232 234 x = (tdata[1] << 27 | tdata[0] << 19) >> 19; 233 235 y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19); ··· 261 259 /* If requested, emulate a scroll wheel by detecting small 262 260 * vertical touch motions. 263 261 */ 264 - if (emulate_scroll_wheel && (input->id.product != 265 - USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) { 262 + if (emulate_scroll_wheel && 263 + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && 264 + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 266 265 unsigned long now = jiffies; 267 266 int step_x = msc->touches[id].scroll_x - x; 268 267 int step_y = msc->touches[id].scroll_y - y; ··· 362 359 input_report_abs(input, ABS_MT_POSITION_X, x); 363 360 input_report_abs(input, ABS_MT_POSITION_Y, y); 364 361 365 - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) 362 + if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 363 + input->id.product == 364 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) 366 365 input_report_abs(input, ABS_MT_PRESSURE, pressure); 367 366 368 367 if (report_undeciphered) { ··· 372 367 input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) 373 368 input_event(input, EV_MSC, MSC_RAW, tdata[7]); 374 369 else if (input->id.product != 375 - USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) 370 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && 371 + input->id.product != 372 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) 376 373 input_event(input, EV_MSC, MSC_RAW, tdata[8]); 377 374 } 378 375 } ··· 500 493 magicmouse_emit_buttons(msc, clicks & 3); 501 494 input_report_rel(input, REL_X, x); 502 495 input_report_rel(input, REL_Y, y); 503 - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 496 + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 497 + input->id.product == 498 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 504 499 input_mt_sync_frame(input); 505 500 input_report_key(input, BTN_MOUSE, clicks & 1); 506 501 } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ ··· 554 545 __set_bit(REL_WHEEL_HI_RES, input->relbit); 555 546 __set_bit(REL_HWHEEL_HI_RES, input->relbit); 556 547 } 557 - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 548 + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 549 + input->id.product == 550 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 558 551 /* If the trackpad has been connected to a Mac, the name is 559 552 * automatically personalized, e.g., "José Expósito's Trackpad". 560 553 * When connected through Bluetooth, the personalized name is ··· 632 621 MOUSE_RES_X); 633 622 input_abs_set_res(input, ABS_MT_POSITION_Y, 634 623 MOUSE_RES_Y); 635 - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 624 + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 625 + input->id.product == 626 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 636 627 input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0); 637 628 input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0); 638 629 input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0); ··· 673 660 input_set_events_per_packet(input, 60); 674 661 675 662 if (report_undeciphered && 676 - input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 663 + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && 664 + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 677 665 __set_bit(EV_MSC, input->evbit); 678 666 __set_bit(MSC_RAW, input->mscbit); 679 667 } ··· 699 685 700 686 /* Magic Trackpad does not give relative data after switching to MT */ 701 687 if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD || 702 - hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && 688 + hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 689 + hi->input->id.product == 690 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && 703 691 field->flags & HID_MAIN_ITEM_RELATIVE) 704 692 return -1; 705 693 ··· 737 721 int ret; 738 722 int feature_size; 739 723 740 - if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 724 + if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 725 + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 741 726 if (hdev->vendor == BT_VENDOR_ID_APPLE) { 742 727 feature_size = sizeof(feature_mt_trackpad2_bt); 743 728 feature = feature_mt_trackpad2_bt; ··· 783 766 784 767 if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE || 785 768 (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 && 786 - hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) 769 + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && 770 + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)) 787 771 return -1; 788 772 789 773 report_enum = &hdev->report_enum[hdev->battery_report_type]; ··· 853 835 854 836 if (id->vendor == USB_VENDOR_ID_APPLE && 855 837 (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || 856 - (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE))) 838 + ((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 839 + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && 840 + hdev->type != HID_TYPE_USBMOUSE))) 857 841 return 0; 858 842 859 843 if (!msc->input) { ··· 870 850 else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) 871 851 report = hid_register_report(hdev, HID_INPUT_REPORT, 872 852 MOUSE2_REPORT_ID, 0); 873 - else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { 853 + else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 854 + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { 874 855 if (id->vendor == BT_VENDOR_ID_APPLE) 875 856 report = hid_register_report(hdev, HID_INPUT_REPORT, 876 857 TRACKPAD2_BT_REPORT_ID, 0); ··· 941 920 */ 942 921 if (hdev->vendor == USB_VENDOR_ID_APPLE && 943 922 (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || 944 - hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && 923 + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || 924 + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && 945 925 *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) { 946 926 hid_info(hdev, 947 927 "fixing up magicmouse battery report descriptor\n"); ··· 973 951 USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, 974 952 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 975 953 USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, 954 + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, 955 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 }, 956 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 957 + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 }, 976 958 { } 977 959 }; 978 960 MODULE_DEVICE_TABLE(hid, magic_mice);
+18 -12
drivers/hid/hid-multitouch.c
··· 31 31 * [1] https://gitlab.freedesktop.org/libevdev/hid-tools 32 32 */ 33 33 34 + #include <linux/bits.h> 34 35 #include <linux/device.h> 35 36 #include <linux/hid.h> 36 37 #include <linux/module.h> ··· 82 81 enum latency_mode { 83 82 HID_LATENCY_NORMAL = 0, 84 83 HID_LATENCY_HIGH = 1, 84 + }; 85 + 86 + enum report_mode { 87 + TOUCHPAD_REPORT_NONE = 0, 88 + TOUCHPAD_REPORT_BUTTONS = BIT(0), 89 + TOUCHPAD_REPORT_CONTACTS = BIT(1), 90 + TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS, 85 91 }; 86 92 87 93 #define MT_IO_FLAGS_RUNNING 0 ··· 1501 1493 struct hid_field *field, 1502 1494 struct hid_usage *usage, 1503 1495 enum latency_mode latency, 1504 - bool surface_switch, 1505 - bool button_switch, 1496 + enum report_mode report_mode, 1506 1497 bool *inputmode_found) 1507 1498 { 1508 1499 struct mt_device *td = hid_get_drvdata(hdev); ··· 1556 1549 return true; 1557 1550 1558 1551 case HID_DG_SURFACESWITCH: 1559 - field->value[index] = surface_switch; 1552 + field->value[index] = !!(report_mode & TOUCHPAD_REPORT_CONTACTS); 1560 1553 return true; 1561 1554 1562 1555 case HID_DG_BUTTONSWITCH: 1563 - field->value[index] = button_switch; 1556 + field->value[index] = !!(report_mode & TOUCHPAD_REPORT_BUTTONS); 1564 1557 return true; 1565 1558 } 1566 1559 ··· 1568 1561 } 1569 1562 1570 1563 static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, 1571 - bool surface_switch, bool button_switch) 1564 + enum report_mode report_mode) 1572 1565 { 1573 1566 struct hid_report_enum *rep_enum; 1574 1567 struct hid_report *rep; ··· 1593 1586 rep->field[i], 1594 1587 usage, 1595 1588 latency, 1596 - surface_switch, 1597 - button_switch, 1589 + report_mode, 1598 1590 &inputmode_found)) 1599 1591 update_report = true; 1600 1592 } ··· 1836 1830 dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", 1837 1831 hdev->name); 1838 1832 1839 - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 1833 + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); 1840 1834 1841 1835 return 0; 1842 1836 } ··· 1848 1842 /* High latency is desirable for power savings during S3/S0ix */ 1849 1843 if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) || 1850 1844 !hid_hw_may_wakeup(hdev)) 1851 - mt_set_modes(hdev, HID_LATENCY_HIGH, false, false); 1845 + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); 1852 1846 else 1853 - mt_set_modes(hdev, HID_LATENCY_HIGH, true, true); 1847 + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_ALL); 1854 1848 1855 1849 return 0; 1856 1850 } ··· 1858 1852 static int mt_reset_resume(struct hid_device *hdev) 1859 1853 { 1860 1854 mt_release_contacts(hdev); 1861 - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 1855 + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); 1862 1856 return 0; 1863 1857 } 1864 1858 ··· 1870 1864 1871 1865 hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); 1872 1866 1873 - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); 1867 + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); 1874 1868 1875 1869 return 0; 1876 1870 }
+1 -1
drivers/hid/hid-picolcd_fb.c
··· 296 296 /* make sure no work is deferred */ 297 297 fb_deferred_io_cleanup(info); 298 298 299 - /* No thridparty should ever unregister our framebuffer! */ 299 + /* No thirdparty should ever unregister our framebuffer! */ 300 300 WARN_ON(fbdata->picolcd != NULL); 301 301 302 302 vfree((u8 *)info->fix.smem_start);
+1 -1
drivers/hid/hid-sensor-custom.c
··· 946 946 947 947 memcpy(real_usage, match->luid, 4); 948 948 949 - /* usage id are all lowcase */ 949 + /* usage id are all lowercase */ 950 950 for (c = real_usage; *c != '\0'; c++) 951 951 *c = tolower(*c); 952 952
+2 -1
drivers/hid/hid-sony.c
··· 1379 1379 u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; 1380 1380 u8 use_hw_blink[MAX_LEDS] = { 0 }; 1381 1381 1382 - BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); 1382 + if (WARN_ON(!(sc->quirks & SONY_LED_SUPPORT))) 1383 + return -EINVAL; 1383 1384 1384 1385 if (sc->quirks & BUZZ_CONTROLLER) { 1385 1386 sc->led_count = 4;
+1 -1
drivers/hid/hid-steam.c
··· 253 253 ID_CONTROLLER_DECK_STATE = 9 254 254 }; 255 255 256 - /* String attribute idenitifiers */ 256 + /* String attribute identifiers */ 257 257 enum { 258 258 ATTRIB_STR_BOARD_SERIAL, 259 259 ATTRIB_STR_UNIT_SERIAL,
+18 -1
drivers/hid/hid-steelseries.c
··· 411 411 "Battery query failed (err: %d)\n", ret); 412 412 } 413 413 414 + static int battery_capacity_to_level(int capacity) 415 + { 416 + if (capacity >= 50) 417 + return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 418 + if (capacity >= 20) 419 + return POWER_SUPPLY_CAPACITY_LEVEL_LOW; 420 + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 421 + } 422 + 414 423 static void steelseries_headset_battery_timer_tick(struct work_struct *work) 415 424 { 416 425 struct steelseries_device *sd = container_of(work, ··· 451 442 case POWER_SUPPLY_PROP_CAPACITY: 452 443 val->intval = sd->battery_capacity; 453 444 break; 445 + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 446 + val->intval = battery_capacity_to_level(sd->battery_capacity); 447 + break; 454 448 default: 455 449 ret = -EINVAL; 456 450 break; ··· 481 469 POWER_SUPPLY_PROP_STATUS, 482 470 POWER_SUPPLY_PROP_SCOPE, 483 471 POWER_SUPPLY_PROP_CAPACITY, 472 + POWER_SUPPLY_PROP_CAPACITY_LEVEL, 484 473 }; 485 474 486 475 static int steelseries_headset_battery_register(struct steelseries_device *sd) ··· 616 603 hid_dbg(sd->hdev, 617 604 "Parsing raw event for Arctis 1 headset (%*ph)\n", size, read_buf); 618 605 if (size < ARCTIS_1_BATTERY_RESPONSE_LEN || 619 - memcmp (read_buf, arctis_1_battery_request, sizeof(arctis_1_battery_request))) 606 + memcmp(read_buf, arctis_1_battery_request, sizeof(arctis_1_battery_request))) { 607 + if (!delayed_work_pending(&sd->battery_work)) 608 + goto request_battery; 620 609 return 0; 610 + } 621 611 if (read_buf[2] == 0x01) { 622 612 connected = false; 623 613 capacity = 100; ··· 647 631 power_supply_changed(sd->battery); 648 632 } 649 633 634 + request_battery: 650 635 spin_lock_irqsave(&sd->lock, flags); 651 636 if (!sd->removed) 652 637 schedule_delayed_work(&sd->battery_work,
+3 -3
drivers/hid/i2c-hid/i2c-hid-of.c
··· 144 144 #endif 145 145 146 146 static const struct i2c_device_id i2c_hid_of_id_table[] = { 147 - { "hid", 0 }, 148 - { "hid-over-i2c", 0 }, 149 - { }, 147 + { "hid" }, 148 + { "hid-over-i2c" }, 149 + { } 150 150 }; 151 151 MODULE_DEVICE_TABLE(i2c, i2c_hid_of_id_table); 152 152
+45
drivers/hid/intel-ish-hid/ipc/pci-ish.c
··· 381 381 382 382 static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); 383 383 384 + static ssize_t base_version_show(struct device *cdev, 385 + struct device_attribute *attr, char *buf) 386 + { 387 + struct ishtp_device *dev = dev_get_drvdata(cdev); 388 + 389 + return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->base_ver.major, 390 + dev->base_ver.minor, dev->base_ver.hotfix, 391 + dev->base_ver.build); 392 + } 393 + static DEVICE_ATTR_RO(base_version); 394 + 395 + static ssize_t project_version_show(struct device *cdev, 396 + struct device_attribute *attr, char *buf) 397 + { 398 + struct ishtp_device *dev = dev_get_drvdata(cdev); 399 + 400 + return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->prj_ver.major, 401 + dev->prj_ver.minor, dev->prj_ver.hotfix, 402 + dev->prj_ver.build); 403 + } 404 + static DEVICE_ATTR_RO(project_version); 405 + 406 + static struct attribute *ish_firmware_attrs[] = { 407 + &dev_attr_base_version.attr, 408 + &dev_attr_project_version.attr, 409 + NULL 410 + }; 411 + 412 + static umode_t firmware_is_visible(struct kobject *kobj, struct attribute *attr, 413 + int i) 414 + { 415 + struct ishtp_device *dev = dev_get_drvdata(kobj_to_dev(kobj)); 416 + 417 + return dev->driver_data->fw_generation ? attr->mode : 0; 418 + } 419 + 420 + static const struct attribute_group ish_firmware_group = { 421 + .name = "firmware", 422 + .attrs = ish_firmware_attrs, 423 + .is_visible = firmware_is_visible, 424 + }; 425 + 426 + __ATTRIBUTE_GROUPS(ish_firmware); 427 + 384 428 static struct pci_driver ish_driver = { 385 429 .name = KBUILD_MODNAME, 386 430 .id_table = ish_pci_tbl, ··· 432 388 .remove = ish_remove, 433 389 .shutdown = ish_shutdown, 434 390 .driver.pm = &ish_pm_ops, 391 + .dev_groups = ish_firmware_groups, 435 392 }; 436 393 437 394 module_pci_driver(ish_driver);
+1 -1
drivers/hid/intel-ish-hid/ishtp-fw-loader.c
··· 793 793 if (rv < 0) 794 794 goto end_err_fw_release; 795 795 796 - /* Step 3: Start ISH main firmware exeuction */ 796 + /* Step 3: Start ISH main firmware execution */ 797 797 798 798 rv = ish_fw_start(client_data); 799 799 if (rv < 0)
+12 -13
drivers/hid/intel-ish-hid/ishtp-hid-client.c
··· 70 70 unsigned char *payload; 71 71 struct device_info *dev_info; 72 72 int i, j; 73 - size_t payload_len, total_len, cur_pos, raw_len; 73 + size_t payload_len, total_len, cur_pos, raw_len, msg_len; 74 74 int report_type; 75 75 struct report_list *reports_list; 76 - char *reports; 76 + struct report *report; 77 77 size_t report_len; 78 78 struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); 79 79 int curr_hid_dev = client_data->cur_hid_dev; ··· 280 280 case HOSTIF_PUBLISH_INPUT_REPORT_LIST: 281 281 report_type = HID_INPUT_REPORT; 282 282 reports_list = (struct report_list *)payload; 283 - reports = (char *)reports_list->reports; 283 + report = reports_list->reports; 284 284 285 285 for (j = 0; j < reports_list->num_of_reports; j++) { 286 - recv_msg = (struct hostif_msg *)(reports + 287 - sizeof(uint16_t)); 288 - report_len = *(uint16_t *)reports; 289 - payload = reports + sizeof(uint16_t) + 290 - sizeof(struct hostif_msg_hdr); 286 + recv_msg = container_of(&report->msg, 287 + struct hostif_msg, hdr); 288 + report_len = report->size; 289 + payload = recv_msg->payload; 291 290 payload_len = report_len - 292 291 sizeof(struct hostif_msg_hdr); 293 292 ··· 303 304 0); 304 305 } 305 306 306 - reports += sizeof(uint16_t) + report_len; 307 + report += sizeof(*report) + payload_len; 307 308 } 308 309 break; 309 310 default: ··· 315 316 316 317 } 317 318 318 - if (!cur_pos && cur_pos + payload_len + 319 - sizeof(struct hostif_msg) < total_len) 319 + msg_len = payload_len + sizeof(struct hostif_msg); 320 + if (!cur_pos && cur_pos + msg_len < total_len) 320 321 ++client_data->multi_packet_cnt; 321 322 322 - cur_pos += payload_len + sizeof(struct hostif_msg); 323 - payload += payload_len + sizeof(struct hostif_msg); 323 + cur_pos += msg_len; 324 + payload += msg_len; 324 325 325 326 } while (cur_pos < total_len); 326 327 }
+7 -4
drivers/hid/intel-ish-hid/ishtp-hid.h
··· 31 31 32 32 struct hostif_msg { 33 33 struct hostif_msg_hdr hdr; 34 + uint8_t payload[]; 34 35 } __packed; 35 36 36 37 struct hostif_msg_to_sensor { ··· 53 52 uint16_t build; 54 53 } __packed; 55 54 55 + struct report { 56 + uint16_t size; 57 + struct hostif_msg_hdr msg; 58 + } __packed; 59 + 56 60 /* struct for ISHTP aggregated input data */ 57 61 struct report_list { 58 62 uint16_t total_size; 59 63 uint8_t num_of_reports; 60 64 uint8_t flags; 61 - struct { 62 - uint16_t size_of_report; 63 - uint8_t report[1]; 64 - } __packed reports[1]; 65 + struct report reports[]; 65 66 } __packed; 66 67 67 68 /* HOSTIF commands */
+1 -1
drivers/hid/intel-ish-hid/ishtp/client.c
··· 863 863 /* Send ipc fragment */ 864 864 ishtp_hdr.length = dev->mtu; 865 865 ishtp_hdr.msg_complete = 0; 866 - /* All fregments submitted to IPC queue with no callback */ 866 + /* All fragments submitted to IPC queue with no callback */ 867 867 ishtp_write_message(dev, &ishtp_hdr, pmsg); 868 868 cl->tx_offs += dev->mtu; 869 869 rem = cl_msg->send_buf.size - cl->tx_offs;
+12
drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
··· 140 140 char *fw_generation; 141 141 }; 142 142 143 + struct ish_version { 144 + u16 major; 145 + u16 minor; 146 + u16 hotfix; 147 + u16 build; 148 + }; 149 + 143 150 /** 144 151 * struct ishtp_device - ISHTP private device struct 145 152 */ ··· 242 235 243 236 /* Dump to trace buffers if enabled*/ 244 237 ishtp_print_log print_log; 238 + 239 + /* Base version of Intel's released firmware */ 240 + struct ish_version base_ver; 241 + /* Vendor-customized project version */ 242 + struct ish_version prj_ver; 245 243 246 244 /* Debug stats */ 247 245 unsigned int ipc_rx_cnt;
+34 -1
drivers/hid/intel-ish-hid/ishtp/loader.c
··· 308 308 return _request_ish_firmware(firmware_p, filename, dev); 309 309 } 310 310 311 + static int copy_manifest(const struct firmware *fw, struct ish_global_manifest *manifest) 312 + { 313 + u32 offset; 314 + 315 + for (offset = 0; offset + sizeof(*manifest) < fw->size; offset += ISH_MANIFEST_ALIGNMENT) { 316 + memcpy(manifest, fw->data + offset, sizeof(*manifest)); 317 + 318 + if (le32_to_cpu(manifest->sig_fourcc) == ISH_GLOBAL_SIG) 319 + return 0; 320 + } 321 + 322 + return -1; 323 + } 324 + 325 + static void copy_ish_version(struct version_in_manifest *src, struct ish_version *dst) 326 + { 327 + dst->major = le16_to_cpu(src->major); 328 + dst->minor = le16_to_cpu(src->minor); 329 + dst->hotfix = le16_to_cpu(src->hotfix); 330 + dst->build = le16_to_cpu(src->build); 331 + } 332 + 311 333 /** 312 334 * ishtp_loader_work() - Load the ISHTP firmware 313 335 * @work: The work structure ··· 358 336 struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), }; 359 337 struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), }; 360 338 union loader_recv_message recv_msg; 339 + struct ish_global_manifest manifest; 361 340 const struct firmware *ish_fw; 362 341 void *dma_bufs[FRAGMENT_MAX_NUM] = {}; 363 342 u32 fragment_size; ··· 395 372 if (rv) 396 373 continue; /* try again if failed */ 397 374 398 - dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", 375 + dev_dbg(dev->devc, "ISH Bootloader Version %u.%u.%u.%u\n", 399 376 recv_msg.query_ack.version_major, 400 377 recv_msg.query_ack.version_minor, 401 378 recv_msg.query_ack.version_hotfix, ··· 413 390 continue; /* try again if failed */ 414 391 415 392 dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); 393 + if (!copy_manifest(ish_fw, &manifest)) { 394 + copy_ish_version(&manifest.base_ver, &dev->base_ver); 395 + copy_ish_version(&manifest.prj_ver, &dev->prj_ver); 396 + dev_info(dev->devc, "FW base version: %u.%u.%u.%u\n", 397 + dev->base_ver.major, dev->base_ver.minor, 398 + dev->base_ver.hotfix, dev->base_ver.build); 399 + dev_info(dev->devc, "FW project version: %u.%u.%u.%u\n", 400 + dev->prj_ver.major, dev->prj_ver.minor, 401 + dev->prj_ver.hotfix, dev->prj_ver.build); 402 + } 416 403 break; 417 404 } while (--retry); 418 405
+34
drivers/hid/intel-ish-hid/ishtp/loader.h
··· 10 10 11 11 #include <linux/bits.h> 12 12 #include <linux/jiffies.h> 13 + #include <linux/sizes.h> 13 14 #include <linux/types.h> 14 15 15 16 #include "ishtp-dev.h" ··· 228 227 * @work: The work structure 229 228 */ 230 229 void ishtp_loader_work(struct work_struct *work); 230 + 231 + /* ISH Manifest alignment in binary is 4KB aligned */ 232 + #define ISH_MANIFEST_ALIGNMENT SZ_4K 233 + 234 + /* Signature for ISH global manifest */ 235 + #define ISH_GLOBAL_SIG 0x47485349 /* FourCC 'I', 'S', 'H', 'G' */ 236 + 237 + struct version_in_manifest { 238 + __le16 major; 239 + __le16 minor; 240 + __le16 hotfix; 241 + __le16 build; 242 + }; 243 + 244 + /** 245 + * struct ish_global_manifest - global manifest for ISH 246 + * @sig_fourcc: Signature FourCC, should be 'I', 'S', 'H', 'G'. 247 + * @len: Length of the manifest. 248 + * @header_version: Version of the manifest header. 249 + * @flags: Flags for additional information. 250 + * @base_ver: Base version of Intel's released firmware. 251 + * @reserved: Reserved space for future use. 252 + * @prj_ver: Vendor-customized project version. 253 + */ 254 + struct ish_global_manifest { 255 + __le32 sig_fourcc; 256 + __le32 len; 257 + __le32 header_version; 258 + __le32 flags; 259 + struct version_in_manifest base_ver; 260 + __le32 reserved[13]; 261 + struct version_in_manifest prj_ver; 262 + }; 231 263 232 264 #endif /* _ISHTP_LOADER_H_ */
+1 -1
drivers/hid/usbhid/hid-core.c
··· 1100 1100 1101 1101 interval = endpoint->bInterval; 1102 1102 1103 - /* Some vendors give fullspeed interval on highspeed devides */ 1103 + /* Some vendors give fullspeed interval on highspeed devices */ 1104 1104 if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL && 1105 1105 dev->speed == USB_SPEED_HIGH) { 1106 1106 interval = fls(endpoint->bInterval*8);
+7 -4
drivers/hid/wacom_wac.c
··· 1353 1353 rotation -= 1800; 1354 1354 1355 1355 input_report_abs(pen_input, ABS_TILT_X, 1356 - (char)frame[7]); 1356 + (signed char)frame[7]); 1357 1357 input_report_abs(pen_input, ABS_TILT_Y, 1358 - (char)frame[8]); 1358 + (signed char)frame[8]); 1359 1359 input_report_abs(pen_input, ABS_Z, rotation); 1360 1360 input_report_abs(pen_input, ABS_WHEEL, 1361 1361 get_unaligned_le16(&frame[11])); ··· 2422 2422 wacom_wac->hid_data.sense_state = value; 2423 2423 return; 2424 2424 case HID_DG_INVERT: 2425 - wacom_wac->hid_data.invert_state = value; 2425 + wacom_wac->hid_data.eraser |= value; 2426 2426 return; 2427 2427 case HID_DG_ERASER: 2428 + wacom_wac->hid_data.eraser |= value; 2429 + fallthrough; 2428 2430 case HID_DG_TIPSWITCH: 2429 2431 wacom_wac->hid_data.tipswitch |= value; 2430 2432 return; ··· 2567 2565 2568 2566 if (entering_range) { /* first in range */ 2569 2567 /* Going into range select tool */ 2570 - if (wacom_wac->hid_data.invert_state) 2568 + if (wacom_wac->hid_data.eraser) 2571 2569 wacom_wac->tool[0] = BTN_TOOL_RUBBER; 2572 2570 else if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) 2573 2571 wacom_wac->tool[0] = BTN_TOOL_PEN; ··· 2621 2619 } 2622 2620 2623 2621 wacom_wac->hid_data.tipswitch = false; 2622 + wacom_wac->hid_data.eraser = false; 2624 2623 2625 2624 input_sync(input); 2626 2625 }
+1 -1
drivers/hid/wacom_wac.h
··· 300 300 __s16 inputmode_index; /* InputMode HID feature index in the report */ 301 301 bool sense_state; 302 302 bool inrange_state; 303 - bool invert_state; 303 + bool eraser; 304 304 bool tipswitch; 305 305 bool barrelswitch; 306 306 bool barrelswitch2;
+12 -9
include/linux/hid.h
··· 359 359 * | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP: 360 360 * | @HID_QUIRK_HAVE_SPECIAL_DRIVER: 361 361 * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE: 362 + * | @HID_QUIRK_IGNORE_SPECIAL_DRIVER 362 363 * | @HID_QUIRK_FULLSPEED_INTERVAL: 363 364 * | @HID_QUIRK_NO_INIT_REPORTS: 364 365 * | @HID_QUIRK_NO_IGNORE: ··· 385 384 #define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19) 386 385 #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20) 387 386 #define HID_QUIRK_NOINVERT BIT(21) 387 + #define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22) 388 388 #define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) 389 389 #define HID_QUIRK_NO_INIT_REPORTS BIT(29) 390 390 #define HID_QUIRK_NO_IGNORE BIT(30) ··· 601 599 struct hid_driver; 602 600 struct hid_ll_driver; 603 601 604 - struct hid_device { /* device report descriptor */ 605 - const __u8 *dev_rdesc; 606 - unsigned dev_rsize; 607 - const __u8 *rdesc; 608 - unsigned rsize; 602 + struct hid_device { 603 + const __u8 *dev_rdesc; /* device report descriptor */ 604 + const __u8 *bpf_rdesc; /* bpf modified report descriptor, if any */ 605 + const __u8 *rdesc; /* currently used report descriptor */ 606 + unsigned int dev_rsize; 607 + unsigned int bpf_rsize; 608 + unsigned int rsize; 609 + unsigned int collection_size; /* Number of allocated hid_collections */ 609 610 struct hid_collection *collection; /* List of HID collections */ 610 - unsigned collection_size; /* Number of allocated hid_collections */ 611 - unsigned maxcollection; /* Number of parsed collections */ 612 - unsigned maxapplication; /* Number of applications */ 611 + unsigned int maxcollection; /* Number of parsed collections */ 612 + unsigned int maxapplication; /* Number of applications */ 613 613 __u16 bus; /* BUS ID */ 614 614 __u16 group; /* Report group */ 615 615 __u32 vendor; /* Vendor ID */ ··· 978 974 struct hid_driver *hdrv); 979 975 bool hid_compare_device_paths(struct hid_device *hdev_a, 980 976 struct hid_device *hdev_b, char separator); 981 - s32 hid_snto32(__u32 value, unsigned n); 982 977 __u32 hid_field_extract(const struct hid_device *hid, __u8 *report, 983 978 unsigned offset, unsigned n); 984 979
+3 -8
include/linux/hid_bpf.h
··· 212 212 void hid_bpf_disconnect_device(struct hid_device *hdev); 213 213 void hid_bpf_destroy_device(struct hid_device *hid); 214 214 int hid_bpf_device_init(struct hid_device *hid); 215 - u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size); 215 + const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size); 216 216 #else /* CONFIG_HID_BPF */ 217 217 static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, 218 218 u8 *data, u32 *size, int interrupt, ··· 228 228 static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} 229 229 static inline void hid_bpf_destroy_device(struct hid_device *hid) {} 230 230 static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; } 231 - /* 232 - * This specialized allocator has to be a macro for its allocations to be 233 - * accounted separately (to have a separate alloc_tag). The typecast is 234 - * intentional to enforce typesafety. 235 - */ 236 - #define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \ 237 - ((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL)) 231 + static inline const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, 232 + unsigned int *size) { return rdesc; } 238 233 239 234 #endif /* CONFIG_HID_BPF */ 240 235
+1 -1
tools/testing/selftests/hid/Makefile
··· 232 232 $(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $< 233 233 $(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@ 234 234 235 - $(OUTPUT)/%.o: %.c $(BPF_SKELS) 235 + $(OUTPUT)/%.o: %.c $(BPF_SKELS) hid_common.h 236 236 $(call msg,CC,,$@) 237 237 $(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@ 238 238
+102 -47
tools/testing/selftests/hid/hid_bpf.c
··· 4 4 #include "hid_common.h" 5 5 #include <bpf/bpf.h> 6 6 7 - struct attach_prog_args { 8 - int prog_fd; 9 - unsigned int hid; 10 - int retval; 11 - int insert_head; 12 - }; 13 - 14 7 struct hid_hw_request_syscall_args { 15 8 __u8 data[10]; 16 9 unsigned int hid; ··· 14 21 }; 15 22 16 23 FIXTURE(hid_bpf) { 17 - int dev_id; 18 - int uhid_fd; 24 + struct uhid_device hid; 19 25 int hidraw_fd; 20 - int hid_id; 21 - pthread_t tid; 22 26 struct hid *skel; 23 27 struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */ 24 28 }; ··· 44 54 FIXTURE_TEARDOWN(hid_bpf) { 45 55 void *uhid_err; 46 56 47 - uhid_destroy(_metadata, self->uhid_fd); 57 + uhid_destroy(_metadata, &self->hid); 48 58 49 59 detach_bpf(self); 50 - pthread_join(self->tid, &uhid_err); 60 + pthread_join(self->hid.tid, &uhid_err); 51 61 } 52 62 #define TEARDOWN_LOG(fmt, ...) do { \ 53 63 TH_LOG(fmt, ##__VA_ARGS__); \ 54 64 hid_bpf_teardown(_metadata, self, variant); \ 55 65 } while (0) 56 66 67 + struct specific_device { 68 + const char test_name[64]; 69 + __u16 bus; 70 + __u32 vid; 71 + __u32 pid; 72 + }; 73 + 57 74 FIXTURE_SETUP(hid_bpf) 58 75 { 59 - time_t t; 76 + const struct specific_device *match = NULL; 60 77 int err; 61 78 62 - /* initialize random number generator */ 63 - srand((unsigned int)time(&t)); 79 + const struct specific_device devices[] = { 80 + { 81 + .test_name = "test_hid_driver_probe", 82 + .bus = BUS_BLUETOOTH, 83 + .vid = 0x05ac, /* USB_VENDOR_ID_APPLE */ 84 + .pid = 0x022c, /* USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI */ 85 + }, { 86 + .test_name = "*", 87 + .bus = BUS_USB, 88 + .vid = 0x0001, 89 + .pid = 0x0a36, 90 + }}; 64 91 65 - self->dev_id = rand() % 1024; 92 + for (int i = 0; i < ARRAY_SIZE(devices); i++) { 93 + match = &devices[i]; 94 + if (!strncmp(_metadata->name, devices[i].test_name, sizeof(devices[i].test_name))) 95 + break; 96 + } 66 97 67 - self->uhid_fd = setup_uhid(_metadata, self->dev_id); 98 + ASSERT_OK_PTR(match); 68 99 69 - /* locate the uev, self, variant);ent file of the created device */ 70 - self->hid_id = get_hid_id(self->dev_id); 71 - ASSERT_GT(self->hid_id, 0) 72 - TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id); 73 - 74 - err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd); 75 - ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err); 100 + err = setup_uhid(_metadata, &self->hid, match->bus, match->vid, match->pid, 101 + rdesc, sizeof(rdesc)); 102 + ASSERT_OK(err); 76 103 } 77 104 78 105 struct test_program { ··· 136 129 ops_hid_id = bpf_map__initial_value(map, NULL); 137 130 ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data"); 138 131 139 - *ops_hid_id = self->hid_id; 132 + *ops_hid_id = self->hid.hid_id; 140 133 } 141 134 142 135 /* we disable the auto-attach feature of all maps because we ··· 164 157 165 158 hid__attach(self->skel); 166 159 167 - self->hidraw_fd = open_hidraw(self->dev_id); 160 + self->hidraw_fd = open_hidraw(&self->hid); 168 161 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 169 162 } 170 163 ··· 199 192 /* inject one event */ 200 193 buf[0] = 1; 201 194 buf[1] = 42; 202 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 195 + uhid_send_event(_metadata, &self->hid, buf, 6); 203 196 204 197 /* check that hid_first_event() was executed */ 205 198 ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1"); ··· 215 208 memset(buf, 0, sizeof(buf)); 216 209 buf[0] = 1; 217 210 buf[1] = 47; 218 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 211 + uhid_send_event(_metadata, &self->hid, buf, 6); 219 212 220 213 /* check that hid_first_event() was executed */ 221 214 ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1"); ··· 246 239 /* inject one event */ 247 240 buf[0] = 1; 248 241 buf[1] = 42; 249 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 242 + uhid_send_event(_metadata, &self->hid, buf, 6); 250 243 251 244 /* read the data from hidraw */ 252 245 memset(buf, 0, sizeof(buf)); ··· 259 252 memset(buf, 0, sizeof(buf)); 260 253 buf[0] = 1; 261 254 buf[1] = 47; 262 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 255 + uhid_send_event(_metadata, &self->hid, buf, 6); 263 256 264 257 /* read the data from hidraw */ 265 258 memset(buf, 0, sizeof(buf)); ··· 310 303 /* inject one event */ 311 304 buf[0] = 1; 312 305 buf[1] = 42; 313 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 306 + uhid_send_event(_metadata, &self->hid, buf, 6); 314 307 315 308 /* read the data from hidraw */ 316 309 memset(buf, 0, sizeof(buf)); ··· 333 326 /* detach the program */ 334 327 detach_bpf(self); 335 328 336 - self->hidraw_fd = open_hidraw(self->dev_id); 329 + self->hidraw_fd = open_hidraw(&self->hid); 337 330 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 338 331 339 332 /* inject another event */ 340 333 memset(buf, 0, sizeof(buf)); 341 334 buf[0] = 1; 342 335 buf[1] = 47; 343 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 336 + uhid_send_event(_metadata, &self->hid, buf, 6); 344 337 345 338 /* read the data from hidraw */ 346 339 memset(buf, 0, sizeof(buf)); ··· 359 352 memset(buf, 0, sizeof(buf)); 360 353 buf[0] = 1; 361 354 buf[1] = 42; 362 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 355 + uhid_send_event(_metadata, &self->hid, buf, 6); 363 356 364 357 /* read the data from hidraw */ 365 358 memset(buf, 0, sizeof(buf)); ··· 389 382 /* inject one event */ 390 383 buf[0] = 1; 391 384 buf[1] = 42; 392 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 385 + uhid_send_event(_metadata, &self->hid, buf, 6); 393 386 394 387 /* read the data from hidraw */ 395 388 memset(buf, 0, sizeof(buf)); ··· 419 412 420 413 LOAD_BPF; 421 414 422 - args.hid = self->hid_id; 415 + args.hid = self->hid.hid_id; 423 416 args.data[0] = 1; /* report ID */ 424 417 args.data[1] = 2; /* report ID */ 425 418 args.data[2] = 42; /* report ID */ ··· 465 458 466 459 LOAD_BPF; 467 460 468 - args.hid = self->hid_id; 461 + args.hid = self->hid.hid_id; 469 462 args.data[0] = 1; /* report ID */ 470 463 args.data[1] = 2; /* report ID */ 471 464 args.data[2] = 42; /* report ID */ ··· 513 506 514 507 LOAD_BPF; 515 508 516 - args.hid = self->hid_id; 509 + args.hid = self->hid.hid_id; 517 510 args.data[0] = 1; /* report ID */ 518 511 519 512 prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request); ··· 546 539 /* inject one event */ 547 540 buf[0] = 1; 548 541 buf[1] = 42; 549 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 542 + uhid_send_event(_metadata, &self->hid, buf, 6); 550 543 551 544 /* read the data from hidraw */ 552 545 memset(buf, 0, sizeof(buf)); ··· 572 565 /* detach the program */ 573 566 detach_bpf(self); 574 567 575 - self->hidraw_fd = open_hidraw(self->dev_id); 568 + self->hidraw_fd = open_hidraw(&self->hid); 576 569 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 577 570 578 571 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); ··· 648 641 /* inject one event */ 649 642 buf[0] = 1; 650 643 buf[1] = 42; 651 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 644 + uhid_send_event(_metadata, &self->hid, buf, 6); 652 645 653 646 /* read the data from hidraw */ 654 647 memset(buf, 0, sizeof(buf)); ··· 674 667 /* detach the program */ 675 668 detach_bpf(self); 676 669 677 - self->hidraw_fd = open_hidraw(self->dev_id); 670 + self->hidraw_fd = open_hidraw(&self->hid); 678 671 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 679 672 680 673 err = write(self->hidraw_fd, buf, 3); ··· 749 742 /* inject one event */ 750 743 buf[0] = 1; 751 744 buf[1] = 42; 752 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 745 + uhid_send_event(_metadata, &self->hid, buf, 6); 753 746 754 747 /* read the data from hidraw */ 755 748 memset(buf, 0, sizeof(buf)); ··· 787 780 /* inject one event */ 788 781 buf[0] = 1; 789 782 buf[1] = 42; 790 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 783 + uhid_send_event(_metadata, &self->hid, buf, 6); 791 784 792 785 /* read the data from hidraw */ 793 786 memset(buf, 0, sizeof(buf)); ··· 823 816 buf[1] = 2; 824 817 buf[2] = 42; 825 818 826 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 819 + uhid_send_event(_metadata, &self->hid, buf, 6); 827 820 828 821 /* read the data from hidraw */ 829 822 memset(buf, 0, sizeof(buf)); ··· 874 867 875 868 /* inject one event */ 876 869 buf[0] = 1; 877 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 870 + uhid_send_event(_metadata, &self->hid, buf, 6); 878 871 879 872 /* read the data from hidraw */ 880 873 memset(buf, 0, sizeof(buf)); ··· 883 876 ASSERT_EQ(buf[1], 1); 884 877 ASSERT_EQ(buf[2], 2); 885 878 ASSERT_EQ(buf[3], 3); 879 + } 880 + 881 + static bool is_using_driver(struct __test_metadata *_metadata, struct uhid_device *hid, 882 + const char *driver) 883 + { 884 + char driver_line[512]; 885 + char uevent[1024]; 886 + char temp[512]; 887 + int fd, nread; 888 + bool found = false; 889 + 890 + sprintf(uevent, "/sys/bus/hid/devices/%04X:%04X:%04X.%04X/uevent", 891 + hid->bus, hid->vid, hid->pid, hid->hid_id); 892 + 893 + fd = open(uevent, O_RDONLY | O_NONBLOCK); 894 + if (fd < 0) { 895 + TH_LOG("couldn't open '%s': %d, %d", uevent, fd, errno); 896 + return false; 897 + } 898 + 899 + sprintf(driver_line, "DRIVER=%s", driver); 900 + 901 + nread = read(fd, temp, ARRAY_SIZE(temp)); 902 + if (nread > 0 && (strstr(temp, driver_line)) != NULL) 903 + found = true; 904 + 905 + close(fd); 906 + 907 + return found; 908 + } 909 + 910 + /* 911 + * Attach hid_driver_probe to the given uhid device, 912 + * check that the device is now using hid-generic. 913 + */ 914 + TEST_F(hid_bpf, test_hid_driver_probe) 915 + { 916 + const struct test_program progs[] = { 917 + { 918 + .name = "hid_test_driver_probe", 919 + }, 920 + }; 921 + 922 + ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "apple")); 923 + 924 + LOAD_PROGRAMS(progs); 925 + 926 + ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "hid-generic")); 886 927 } 887 928 888 929 /*
+75 -37
tools/testing/selftests/hid/hid_common.h
··· 19 19 __typeof__(b) _b = (b); \ 20 20 _a < _b ? _a : _b; }) 21 21 22 + struct uhid_device { 23 + int dev_id; /* uniq (random) number to identify the device */ 24 + int uhid_fd; 25 + int hid_id; /* HID device id in the system */ 26 + __u16 bus; 27 + __u32 vid; 28 + __u32 pid; 29 + pthread_t tid; /* thread for reading uhid events */ 30 + }; 31 + 22 32 static unsigned char rdesc[] = { 23 33 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 24 34 0x09, 0x21, /* Usage (Vendor Usage 0x21) */ ··· 132 122 } 133 123 } 134 124 135 - static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb) 125 + static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb, 126 + __u16 bus, __u32 vid, __u32 pid, __u8 *rdesc, 127 + size_t rdesc_size) 136 128 { 137 129 struct uhid_event ev; 138 130 char buf[25]; ··· 145 133 ev.type = UHID_CREATE; 146 134 strcpy((char *)ev.u.create.name, buf); 147 135 ev.u.create.rd_data = rdesc; 148 - ev.u.create.rd_size = sizeof(rdesc); 149 - ev.u.create.bus = BUS_USB; 150 - ev.u.create.vendor = 0x0001; 151 - ev.u.create.product = 0x0a37; 136 + ev.u.create.rd_size = rdesc_size; 137 + ev.u.create.bus = bus; 138 + ev.u.create.vendor = vid; 139 + ev.u.create.product = pid; 152 140 ev.u.create.version = 0; 153 141 ev.u.create.country = 0; 154 142 ··· 158 146 return uhid_write(_metadata, fd, &ev); 159 147 } 160 148 161 - static void uhid_destroy(struct __test_metadata *_metadata, int fd) 149 + static void uhid_destroy(struct __test_metadata *_metadata, struct uhid_device *hid) 162 150 { 163 151 struct uhid_event ev; 164 152 165 153 memset(&ev, 0, sizeof(ev)); 166 154 ev.type = UHID_DESTROY; 167 155 168 - uhid_write(_metadata, fd, &ev); 156 + uhid_write(_metadata, hid->uhid_fd, &ev); 169 157 } 170 158 171 159 static int uhid_event(struct __test_metadata *_metadata, int fd) ··· 293 281 return 0; 294 282 } 295 283 296 - static int uhid_send_event(struct __test_metadata *_metadata, int fd, __u8 *buf, size_t size) 284 + static int uhid_send_event(struct __test_metadata *_metadata, struct uhid_device *hid, 285 + __u8 *buf, size_t size) 297 286 { 298 287 struct uhid_event ev; 299 288 ··· 307 294 308 295 memcpy(ev.u.input2.data, buf, size); 309 296 310 - return uhid_write(_metadata, fd, &ev); 297 + return uhid_write(_metadata, hid->uhid_fd, &ev); 311 298 } 312 299 313 - static int setup_uhid(struct __test_metadata *_metadata, int rand_nb) 300 + static bool match_sysfs_device(struct uhid_device *hid, const char *workdir, struct dirent *dir) 314 301 { 315 - int fd; 316 - const char *path = "/dev/uhid"; 317 - int ret; 318 - 319 - fd = open(path, O_RDWR | O_CLOEXEC); 320 - ASSERT_GE(fd, 0) TH_LOG("open uhid-cdev failed; %d", fd); 321 - 322 - ret = uhid_create(_metadata, fd, rand_nb); 323 - ASSERT_EQ(0, ret) { 324 - TH_LOG("create uhid device failed: %d", ret); 325 - close(fd); 326 - } 327 - 328 - return fd; 329 - } 330 - 331 - static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *dir) 332 - { 333 - const char *target = "0003:0001:0A37.*"; 302 + char target[20] = ""; 334 303 char phys[512]; 335 304 char uevent[1024]; 336 305 char temp[512]; 337 306 int fd, nread; 338 307 bool found = false; 308 + 309 + snprintf(target, sizeof(target), "%04X:%04X:%04X.*", hid->bus, hid->vid, hid->pid); 339 310 340 311 if (fnmatch(target, dir->d_name, 0)) 341 312 return false; ··· 331 334 if (fd < 0) 332 335 return false; 333 336 334 - sprintf(phys, "PHYS=%d", dev_id); 337 + sprintf(phys, "PHYS=%d", hid->dev_id); 335 338 336 339 nread = read(fd, temp, ARRAY_SIZE(temp)); 337 340 if (nread > 0 && (strstr(temp, phys)) != NULL) ··· 342 345 return found; 343 346 } 344 347 345 - static int get_hid_id(int dev_id) 348 + static int get_hid_id(struct uhid_device *hid) 346 349 { 347 350 const char *workdir = "/sys/devices/virtual/misc/uhid"; 348 351 const char *str_id; ··· 357 360 d = opendir(workdir); 358 361 if (d) { 359 362 while ((dir = readdir(d)) != NULL) { 360 - if (!match_sysfs_device(dev_id, workdir, dir)) 363 + if (!match_sysfs_device(hid, workdir, dir)) 361 364 continue; 362 365 363 - str_id = dir->d_name + sizeof("0003:0001:0A37."); 366 + str_id = dir->d_name + sizeof("0000:0000:0000."); 364 367 found = (int)strtol(str_id, NULL, 16); 365 368 366 369 break; ··· 374 377 return found; 375 378 } 376 379 377 - static int get_hidraw(int dev_id) 380 + static int get_hidraw(struct uhid_device *hid) 378 381 { 379 382 const char *workdir = "/sys/devices/virtual/misc/uhid"; 380 383 char sysfs[1024]; ··· 391 394 continue; 392 395 393 396 while ((dir = readdir(d)) != NULL) { 394 - if (!match_sysfs_device(dev_id, workdir, dir)) 397 + if (!match_sysfs_device(hid, workdir, dir)) 395 398 continue; 396 399 397 400 sprintf(sysfs, "%s/%s/hidraw", workdir, dir->d_name); ··· 418 421 return found; 419 422 } 420 423 421 - static int open_hidraw(int dev_id) 424 + static int open_hidraw(struct uhid_device *hid) 422 425 { 423 426 int hidraw_number; 424 427 char hidraw_path[64] = { 0 }; 425 428 426 - hidraw_number = get_hidraw(dev_id); 429 + hidraw_number = get_hidraw(hid); 427 430 if (hidraw_number < 0) 428 431 return hidraw_number; 429 432 430 433 /* open hidraw node to check the other side of the pipe */ 431 434 sprintf(hidraw_path, "/dev/hidraw%d", hidraw_number); 432 435 return open(hidraw_path, O_RDWR | O_NONBLOCK); 436 + } 437 + 438 + static int setup_uhid(struct __test_metadata *_metadata, struct uhid_device *hid, 439 + __u16 bus, __u32 vid, __u32 pid, const __u8 *rdesc, size_t rdesc_size) 440 + { 441 + const char *path = "/dev/uhid"; 442 + time_t t; 443 + int ret; 444 + 445 + /* initialize random number generator */ 446 + srand((unsigned int)time(&t)); 447 + 448 + hid->dev_id = rand() % 1024; 449 + hid->bus = bus; 450 + hid->vid = vid; 451 + hid->pid = pid; 452 + 453 + hid->uhid_fd = open(path, O_RDWR | O_CLOEXEC); 454 + ASSERT_GE(hid->uhid_fd, 0) TH_LOG("open uhid-cdev failed; %d", hid->uhid_fd); 455 + 456 + ret = uhid_create(_metadata, hid->uhid_fd, hid->dev_id, bus, vid, pid, 457 + (__u8 *)rdesc, rdesc_size); 458 + ASSERT_EQ(0, ret) { 459 + TH_LOG("create uhid device failed: %d", ret); 460 + close(hid->uhid_fd); 461 + return ret; 462 + } 463 + 464 + /* locate the uevent file of the created device */ 465 + hid->hid_id = get_hid_id(hid); 466 + ASSERT_GT(hid->hid_id, 0) 467 + TH_LOG("Could not locate uhid device id: %d", hid->hid_id); 468 + 469 + ret = uhid_start_listener(_metadata, &hid->tid, hid->uhid_fd); 470 + ASSERT_EQ(0, ret) { 471 + TH_LOG("could not start udev listener: %d", ret); 472 + close(hid->uhid_fd); 473 + return ret; 474 + } 475 + 476 + return 0; 433 477 }
+10 -26
tools/testing/selftests/hid/hidraw.c
··· 9 9 #endif /* HIDIOCREVOKE */ 10 10 11 11 FIXTURE(hidraw) { 12 - int dev_id; 13 - int uhid_fd; 12 + struct uhid_device hid; 14 13 int hidraw_fd; 15 - int hid_id; 16 - pthread_t tid; 17 14 }; 18 15 static void close_hidraw(FIXTURE_DATA(hidraw) * self) 19 16 { ··· 22 25 FIXTURE_TEARDOWN(hidraw) { 23 26 void *uhid_err; 24 27 25 - uhid_destroy(_metadata, self->uhid_fd); 28 + uhid_destroy(_metadata, &self->hid); 26 29 27 30 close_hidraw(self); 28 - pthread_join(self->tid, &uhid_err); 31 + pthread_join(self->hid.tid, &uhid_err); 29 32 } 30 33 #define TEARDOWN_LOG(fmt, ...) do { \ 31 34 TH_LOG(fmt, ##__VA_ARGS__); \ ··· 34 37 35 38 FIXTURE_SETUP(hidraw) 36 39 { 37 - time_t t; 38 40 int err; 39 41 40 - /* initialize random number generator */ 41 - srand((unsigned int)time(&t)); 42 + err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc)); 43 + ASSERT_OK(err); 42 44 43 - self->dev_id = rand() % 1024; 44 - 45 - self->uhid_fd = setup_uhid(_metadata, self->dev_id); 46 - 47 - /* locate the uev, self, variant);ent file of the created device */ 48 - self->hid_id = get_hid_id(self->dev_id); 49 - ASSERT_GT(self->hid_id, 0) 50 - TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id); 51 - 52 - err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd); 53 - ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err); 54 - 55 - self->hidraw_fd = open_hidraw(self->dev_id); 45 + self->hidraw_fd = open_hidraw(&self->hid); 56 46 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 57 47 } 58 48 ··· 63 79 /* inject one event */ 64 80 buf[0] = 1; 65 81 buf[1] = 42; 66 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 82 + uhid_send_event(_metadata, &self->hid, buf, 6); 67 83 68 84 /* read the data from hidraw */ 69 85 memset(buf, 0, sizeof(buf)); ··· 85 101 /* inject one event */ 86 102 buf[0] = 1; 87 103 buf[1] = 42; 88 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 104 + uhid_send_event(_metadata, &self->hid, buf, 6); 89 105 90 106 /* read the data from hidraw */ 91 107 memset(buf, 0, sizeof(buf)); ··· 101 117 /* inject one other event */ 102 118 buf[0] = 1; 103 119 buf[1] = 43; 104 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 120 + uhid_send_event(_metadata, &self->hid, buf, 6); 105 121 106 122 /* read the data from hidraw */ 107 123 memset(buf, 0, sizeof(buf)); ··· 145 161 /* inject one event */ 146 162 buf[0] = 1; 147 163 buf[1] = 42; 148 - uhid_send_event(_metadata, self->uhid_fd, buf, 6); 164 + uhid_send_event(_metadata, &self->hid, buf, 6); 149 165 150 166 while (true) { 151 167 ready = poll(pfds, 1, 5000);
+12
tools/testing/selftests/hid/progs/hid.c
··· 598 598 struct hid_bpf_ops test_infinite_loop_input_report = { 599 599 .hid_device_event = (void *)hid_test_infinite_loop_input_report, 600 600 }; 601 + 602 + SEC("?struct_ops.s/hid_rdesc_fixup") 603 + int BPF_PROG(hid_test_driver_probe, struct hid_bpf_ctx *hid_ctx) 604 + { 605 + hid_ctx->hid->quirks |= HID_QUIRK_IGNORE_SPECIAL_DRIVER; 606 + return 0; 607 + } 608 + 609 + SEC(".struct_ops.link") 610 + struct hid_bpf_ops test_driver_probe = { 611 + .hid_rdesc_fixup = (void *)hid_test_driver_probe, 612 + };
+5 -1
tools/testing/selftests/hid/progs/hid_bpf_helpers.h
··· 84 84 struct hid_device *hdev; 85 85 }; 86 86 87 + #define BIT(n) (1U << n) 88 + 87 89 #ifndef BPF_F_BEFORE 88 - #define BPF_F_BEFORE (1U << 3) 90 + #define BPF_F_BEFORE BIT(3) 89 91 #endif 92 + 93 + #define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22) 90 94 91 95 /* following are kfuncs exported by HID for HID-BPF */ 92 96 extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,