diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2020-11-17 18:13:23 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2020-11-17 18:13:23 -0800 |
commit | 05909cd9a0c8811731b38697af13075e8954314f (patch) | |
tree | aa5306e756666407c95067b20b21b32ff27fd11a /drivers/hid | |
parent | c7f0169e3bd274e576f6aaeee86ad2adf7bb14b5 (diff) | |
parent | bbf5c979011a099af5dc76498918ed7df445635b (diff) |
Merge tag 'v5.9' into next
Sync up with mainline to bring in the latest DTS files.
Diffstat (limited to 'drivers/hid')
38 files changed, 965 insertions, 354 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 34f07371716d..05315b434276 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -9,7 +9,7 @@ config HID tristate "HID bus support" depends on INPUT default y - ---help--- + help A human interface device (HID) is a type of computer device that interacts directly with and takes input from humans. The term "HID" most commonly used to refer to the USB-HID specification, but other @@ -20,7 +20,7 @@ config HID removed from the HID bus by the transport-layer drivers, such as usbhid (USB_HID) and hidp (BT_HIDP). - For docs and specs, see http://www.usb.org/developers/hidpage/ + For docs and specs, see https://www.usb.org/developers/hidpage/ If unsure, say Y. @@ -31,7 +31,7 @@ config HID_BATTERY_STRENGTH depends on HID select POWER_SUPPLY default n - ---help--- + help This option adds support of reporting battery strength (for HID devices that support this feature) through power_supply class so that userspace tools, such as upower, can display it. @@ -39,10 +39,10 @@ config HID_BATTERY_STRENGTH config HIDRAW bool "/dev/hidraw raw HID device support" depends on HID - ---help--- + help Say Y here if you want to support HID devices (from the USB specification standpoint) that aren't strictly user interface - devices, like monitor controls and Uninterruptable Power Supplies. + devices, like monitor controls and Uninterruptible Power Supplies. This module supports these devices separately using a separate event interface on /dev/hidraw. @@ -59,7 +59,7 @@ config UHID tristate "User-space I/O driver support for HID subsystem" depends on HID default n - ---help--- + help Say Y here if you want to provide HID I/O Drivers from user-space. This allows to write I/O drivers in user-space and feed the data from the device into the kernel. The kernel parses the HID reports, loads the @@ -80,7 +80,7 @@ config HID_GENERIC tristate "Generic HID driver" depends on HID default HID - ---help--- + help Support for generic devices on the HID bus. This includes most keyboards and mice, joysticks, tablets and digitizers. @@ -96,13 +96,13 @@ config HID_A4TECH tristate "A4 tech mice" depends on HID default !EXPERT - ---help--- + help Support for A4 tech X5 and WOP-35 / Trust 450L mice. config HID_ACCUTOUCH tristate "Accutouch touch device" depends on USB_HID - ---help--- + help This selects a driver for the Accutouch 2216 touch controller. The driver works around a problem in the reported device capabilities @@ -114,14 +114,14 @@ config HID_ACCUTOUCH config HID_ACRUX tristate "ACRUX game controller support" depends on HID - ---help--- + help Say Y here if you want to enable support for ACRUX game controllers. config HID_ACRUX_FF bool "ACRUX force feedback support" depends on HID_ACRUX select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you want to enable force feedback support for ACRUX game controllers. @@ -129,7 +129,7 @@ config HID_APPLE tristate "Apple {i,Power,Mac}Books" depends on HID default !EXPERT - ---help--- + help Support for some Apple devices which less or more break HID specification. @@ -139,7 +139,7 @@ config HID_APPLE config HID_APPLEIR tristate "Apple infrared receiver" depends on (USB_HID) - ---help--- + help Support for Apple infrared remote control. All the Apple computers from 2005 onwards include such a port, except the unibody Macbook (2009), and Mac Pros. This receiver is also used in the Apple TV set-top box @@ -149,10 +149,11 @@ config HID_APPLEIR config HID_ASUS tristate "Asus" + depends on USB_HID depends on LEDS_CLASS depends on ASUS_WMI || ASUS_WMI=n select POWER_SUPPLY - ---help--- + help Support for Asus notebook built-in keyboard and touchpad via i2c, and the Asus Republic of Gamers laptop keyboard special keys. @@ -165,21 +166,21 @@ config HID_ASUS config HID_AUREAL tristate "Aureal" depends on HID - ---help--- + help Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes. config HID_BELKIN tristate "Belkin Flip KVM and Wireless keyboard" depends on HID default !EXPERT - ---help--- + help Support for Belkin Flip KVM and Wireless keyboard. config HID_BETOP_FF tristate "Betop Production Inc. force feedback support" depends on USB_HID select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you want to enable force feedback support for devices by BETOP Production Ltd. Currently the following devices are known to be supported: @@ -201,20 +202,20 @@ config HID_CHERRY tristate "Cherry Cymotion keyboard" depends on HID default !EXPERT - ---help--- + help Support for Cherry Cymotion keyboard. config HID_CHICONY tristate "Chicony devices" depends on HID default !EXPERT - ---help--- + help Support for Chicony Tactical pad and special keys on Chicony keyboards. config HID_CORSAIR tristate "Corsair devices" depends on HID && USB && LEDS_CLASS - ---help--- + help Support for Corsair devices that are not fully compliant with the HID standard. @@ -246,7 +247,7 @@ config HID_PRODIKEYS tristate "Prodikeys PC-MIDI Keyboard support" depends on HID && SND select SND_RAWMIDI - ---help--- + help Support for Prodikeys PC-MIDI Keyboard device support. Say Y here to enable support for this device. - Prodikeys PC-MIDI keyboard. @@ -260,14 +261,14 @@ config HID_PRODIKEYS config HID_CMEDIA tristate "CMedia CM6533 HID audio jack controls" depends on HID - ---help--- + help Support for CMedia CM6533 HID audio jack controls. config HID_CP2112 tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" depends on USB_HID && HIDRAW && I2C && GPIOLIB select GPIOLIB_IRQCHIP - ---help--- + help Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. This is a HID device driver which registers as an i2c adapter and gpiochip to expose these functions of the CP2112. The @@ -286,13 +287,13 @@ config HID_CYPRESS tristate "Cypress mouse and barcode readers" depends on HID default !EXPERT - ---help--- + help Support for cypress mouse and barcode readers. config HID_DRAGONRISE tristate "DragonRise Inc. game controller" depends on HID - ---help--- + help Say Y here if you have DragonRise Inc. game controllers. These might be branded as: - Tesun USB-703 @@ -304,7 +305,7 @@ config DRAGONRISE_FF bool "DragonRise Inc. force feedback" depends on HID_DRAGONRISE select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you want to enable force feedback support for DragonRise Inc. game controllers. @@ -312,7 +313,7 @@ config HID_EMS_FF tristate "EMS Production Inc. force feedback support" depends on HID select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you want to enable force feedback support for devices by EMS Production Ltd. Currently the following devices are known to be supported: @@ -321,7 +322,7 @@ config HID_EMS_FF config HID_ELAN tristate "ELAN USB Touchpad Support" depends on LEDS_CLASS && USB_HID - ---help--- + help Say Y to enable support for the USB ELAN touchpad Currently the following devices are known to be supported: - HP Pavilion X2 10-p0XX. @@ -329,7 +330,7 @@ config HID_ELAN config HID_ELECOM tristate "ELECOM HID devices" depends on HID - ---help--- + help Support for ELECOM devices: - BM084 Bluetooth Mouse - EX-G Trackballs (M-XT3DRBK, M-XT3URBK) @@ -339,7 +340,7 @@ config HID_ELECOM config HID_ELO tristate "ELO USB 4000/4500 touchscreen" depends on USB_HID - ---help--- + help Support for the ELO USB 4000/4500 touchscreens. Note that this is for different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO. @@ -347,19 +348,19 @@ config HID_EZKEY tristate "Ezkey BTC 8193 keyboard" depends on HID default !EXPERT - ---help--- + help Support for Ezkey BTC 8193 keyboard. config HID_GEMBIRD tristate "Gembird Joypad" depends on HID - ---help--- + help Support for Gembird JPD-DualForce 2. config HID_GFRM tristate "Google Fiber TV Box remote control support" depends on HID - ---help--- + help Support for Google Fiber TV Box remote controls config HID_GLORIOUS @@ -372,7 +373,7 @@ config HID_GLORIOUS config HID_HOLTEK tristate "Holtek HID devices" depends on USB_HID - ---help--- + help Support for Holtek based devices: - Holtek On Line Grip based game controller - Trust GXT 18 Gaming Keyboard @@ -386,20 +387,20 @@ config HOLTEK_FF bool "Holtek On Line Grip force feedback support" depends on HID_HOLTEK select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. config HID_GOOGLE_HAMMER tristate "Google Hammer Keyboard" depends on USB_HID && LEDS_CLASS && CROS_EC - ---help--- + help Say Y here if you have a Google Hammer device. config HID_GT683R tristate "MSI GT68xR LED support" depends on LEDS_CLASS && USB_HID - ---help--- + help Say Y here if you want to enable support for the three MSI GT68xR LEDs This driver support following modes: @@ -413,7 +414,7 @@ config HID_GT683R config HID_KEYTOUCH tristate "Keytouch HID devices" depends on HID - ---help--- + help Support for Keytouch HID devices not fully compliant with the specification. Currently supported: - Keytouch IEC 60945 @@ -421,7 +422,7 @@ config HID_KEYTOUCH config HID_KYE tristate "KYE/Genius devices" depends on HID - ---help--- + help Support for KYE/Genius devices not fully compliant with HID standard: - Ergo Mouse - EasyPen i405X tablet @@ -431,13 +432,13 @@ config HID_KYE config HID_UCLOGIC tristate "UC-Logic" depends on USB_HID - ---help--- + help Support for UC-Logic and Huion tablets. config HID_WALTOP tristate "Waltop" depends on HID - ---help--- + help Support for Waltop tablets. config HID_VIEWSONIC @@ -449,13 +450,13 @@ config HID_VIEWSONIC config HID_GYRATION tristate "Gyration remote control" depends on HID - ---help--- + help Support for Gyration remote control. config HID_ICADE tristate "ION iCade arcade controller" depends on HID - ---help--- + help Support for the ION iCade arcade controller to work as a joystick. To compile this driver as a module, choose M here: the @@ -465,13 +466,13 @@ config HID_ITE tristate "ITE devices" depends on HID default !EXPERT - ---help--- + help Support for ITE devices not fully compliant with HID standard. config HID_JABRA tristate "Jabra USB HID Driver" depends on HID - ---help--- + help Support for Jabra USB HID devices. Prevents mapping of vendor defined HID usages to input events. Without @@ -482,27 +483,27 @@ config HID_JABRA config HID_TWINHAN tristate "Twinhan IR remote control" depends on HID - ---help--- + help Support for Twinhan IR remote control. config HID_KENSINGTON tristate "Kensington Slimblade Trackball" depends on HID default !EXPERT - ---help--- + help Support for Kensington Slimblade Trackball. config HID_LCPOWER tristate "LC-Power" depends on HID - ---help--- + help Support for LC-Power RC1000MCE RF remote control. config HID_LED tristate "Simple RGB LED support" depends on HID depends on LEDS_CLASS - ---help--- + help Support for simple RGB LED devices. Currently supported are: - Riso Kagaku Webmail Notifier - Dream Cheeky Webmail Notifier and Friends Alert @@ -518,7 +519,7 @@ config HID_LENOVO depends on HID select NEW_LEDS select LEDS_CLASS - ---help--- + help Support for IBM/Lenovo devices that are not fully compliant with HID standard. Say Y if you want support for horizontal scrolling of the IBM/Lenovo @@ -534,18 +535,18 @@ config HID_LOGITECH depends on HID depends on LEDS_CLASS default !EXPERT - ---help--- + help Support for Logitech devices that are not fully compliant with HID standard. config HID_LOGITECH_DJ - tristate "Logitech Unifying receivers full support" + tristate "Logitech receivers full support" depends on USB_HID depends on HIDRAW depends on HID_LOGITECH select HID_LOGITECH_HIDPP - ---help--- - Say Y if you want support for Logitech Unifying receivers and devices. - Unifying receivers are capable of pairing up to 6 Logitech compliant + help + Say Y if you want support for Logitech receivers and devices. + Logitech receivers are capable of pairing multiple Logitech compliant devices to the same receiver. Without this driver it will be handled by generic USB_HID driver and all incoming events will be multiplexed into a single mouse and a single keyboard device. @@ -554,7 +555,7 @@ config HID_LOGITECH_HIDPP tristate "Logitech HID++ devices support" depends on HID_LOGITECH select POWER_SUPPLY - ---help--- + help Support for Logitech devices relyingon the HID++ Logitech specification Say Y if you want support for Logitech devices relying on the HID++ @@ -620,7 +621,7 @@ config LOGIWHEELS_FF config HID_MAGICMOUSE tristate "Apple Magic Mouse/Trackpad multi-touch support" depends on HID - ---help--- + help Support for the Apple Magic Mouse/Trackpad multi-touch. Say Y here if you want support for the multi-touch features of the @@ -629,7 +630,7 @@ config HID_MAGICMOUSE config HID_MALTRON tristate "Maltron L90 keyboard" depends on HID - ---help--- + help Adds support for the volume up, volume down, mute, and play/pause buttons of the Maltron L90 keyboard. @@ -637,7 +638,7 @@ config HID_MAYFLASH tristate "Mayflash game controller adapter force feedback" depends on HID select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have HJZ Mayflash PS3 game controller adapters and want to enable force feedback support. @@ -645,7 +646,7 @@ config HID_REDRAGON tristate "Redragon keyboards" depends on HID default !EXPERT - ---help--- + help Support for Redragon keyboards that need fix-ups to work properly. config HID_MICROSOFT @@ -653,20 +654,20 @@ config HID_MICROSOFT depends on HID default !EXPERT select INPUT_FF_MEMLESS - ---help--- + help Support for Microsoft devices that are not fully compliant with HID standard. config HID_MONTEREY tristate "Monterey Genius KB29E keyboard" depends on HID default !EXPERT - ---help--- + help Support for Monterey Genius KB29E. config HID_MULTITOUCH tristate "HID Multitouch panels" depends on HID - ---help--- + help Generic support for HID multitouch panels. Say Y here if you have one of the following devices: @@ -711,20 +712,20 @@ config HID_MULTITOUCH config HID_NTI tristate "NTI keyboard adapters" - ---help--- + help Support for the "extra" Sun keyboard keys on keyboards attached through Network Technologies USB-SUN keyboard adapters. config HID_NTRIG tristate "N-Trig touch screen" depends on USB_HID - ---help--- + help Support for N-Trig touch screen. config HID_ORTEK tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad" depends on HID - ---help--- + help There are certain devices which have LogicalMaximum wrong in the keyboard usage page of their report descriptor. The most prevailing ones so far are manufactured by Ortek, thus the name of the driver. Currently @@ -737,7 +738,7 @@ config HID_ORTEK config HID_PANTHERLORD tristate "Pantherlord/GreenAsia game controller" depends on HID - ---help--- + help Say Y here if you have a PantherLord/GreenAsia based game controller or adapter. @@ -745,14 +746,14 @@ config PANTHERLORD_FF bool "Pantherlord force feedback support" depends on HID_PANTHERLORD select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a PantherLord/GreenAsia based game controller or adapter and want to enable force feedback support for it. config HID_PENMOUNT tristate "Penmount touch device" depends on USB_HID - ---help--- + help This selects a driver for the PenMount 6000 touch controller. The driver works around a problem in the report descript allowing @@ -763,13 +764,13 @@ config HID_PENMOUNT config HID_PETALYNX tristate "Petalynx Maxter remote control" depends on HID - ---help--- + help Support for Petalynx Maxter remote control. config HID_PICOLCD tristate "PicoLCD (graphic version)" depends on HID - ---help--- + help This provides support for Minibox PicoLCD devices, currently only the graphical ones are supported. @@ -795,7 +796,7 @@ config HID_PICOLCD_FB select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS - ---help--- + help Provide access to PicoLCD's 256x64 monochrome display via a framebuffer device. @@ -804,7 +805,7 @@ config HID_PICOLCD_BACKLIGHT default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y - ---help--- + help Provide access to PicoLCD's backlight control via backlight class. @@ -813,7 +814,7 @@ config HID_PICOLCD_LCD default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y - ---help--- + help Provide access to PicoLCD's LCD contrast via lcd class. config HID_PICOLCD_LEDS @@ -821,7 +822,7 @@ config HID_PICOLCD_LEDS default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y - ---help--- + help Provide access to PicoLCD's GPO pins via leds class. config HID_PICOLCD_CIR @@ -829,13 +830,13 @@ config HID_PICOLCD_CIR default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=RC_CORE || RC_CORE=y - ---help--- + help Provide access to PicoLCD's CIR interface via remote control (LIRC). config HID_PLANTRONICS tristate "Plantronics USB HID Driver" depends on HID - ---help--- + help Provides HID support for Plantronics USB audio devices. Correctly maps vendor unique volume up/down HID usages to KEY_VOLUMEUP and KEY_VOLUMEDOWN events and prevents core mapping @@ -846,21 +847,21 @@ config HID_PLANTRONICS config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" depends on HID - ---help--- + help Support for Primax devices that are not fully compliant with the HID standard. config HID_RETRODE tristate "Retrode 2 USB adapter for vintage video games" depends on USB_HID - ---help--- + help Support for * Retrode 2 cartridge and controller adapter config HID_ROCCAT tristate "Roccat device support" depends on USB_HID - ---help--- + help Support for Roccat devices. Say Y here if you have a Roccat mouse or keyboard and want support for its special functionalities. @@ -868,7 +869,7 @@ config HID_ROCCAT config HID_SAITEK tristate "Saitek (Mad Catz) non-fully HID-compliant devices" depends on HID - ---help--- + help Support for Saitek devices that are not fully compliant with the HID standard. @@ -880,7 +881,7 @@ config HID_SAITEK config HID_SAMSUNG tristate "Samsung InfraRed remote control or keyboards" depends on HID - ---help--- + help Support for Samsung InfraRed remote control or keyboards. config HID_SONY @@ -889,7 +890,7 @@ config HID_SONY depends on NEW_LEDS depends on LEDS_CLASS select POWER_SUPPLY - ---help--- + help Support for * Sony PS3 6-axis controllers @@ -902,21 +903,21 @@ config SONY_FF bool "Sony PS2/3/4 accessories force feedback support" depends on HID_SONY select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a Sony PS2/3/4 accessory and want to enable force feedback support for it. config HID_SPEEDLINK tristate "Speedlink VAD Cezanne mouse support" depends on HID - ---help--- + help Support for Speedlink Vicious and Divine Cezanne mouse. config HID_STEAM tristate "Steam Controller support" depends on HID select POWER_SUPPLY - ---help--- + help Say Y here if you have a Steam Controller if you want to use it without running the Steam Client. It supports both the wired and the wireless adaptor. @@ -924,13 +925,13 @@ config HID_STEAM config HID_STEELSERIES tristate "Steelseries SRW-S1 steering wheel support" depends on HID - ---help--- + help Support for Steelseries SRW-S1 steering wheel config HID_SUNPLUS tristate "Sunplus wireless desktop" depends on HID - ---help--- + help Support for Sunplus wireless desktop. config HID_RMI @@ -941,7 +942,7 @@ config HID_RMI select RMI4_F11 select RMI4_F12 select RMI4_F30 - ---help--- + help Support for Synaptics RMI4 touchpads. Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid and want support for its special functionalities. @@ -949,7 +950,7 @@ config HID_RMI config HID_GREENASIA tristate "GreenAsia (Product ID 0x12) game controller support" depends on HID - ---help--- + help Say Y here if you have a GreenAsia (Product ID 0x12) based game controller or adapter. @@ -957,7 +958,7 @@ config GREENASIA_FF bool "GreenAsia (Product ID 0x12) force feedback support" depends on HID_GREENASIA select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a GreenAsia (Product ID 0x12) based game controller (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter and want to enable force feedback support for it. @@ -965,13 +966,13 @@ config GREENASIA_FF config HID_HYPERV_MOUSE tristate "Microsoft Hyper-V mouse driver" depends on HYPERV - ---help--- + help Select this option to enable the Hyper-V mouse driver. config HID_SMARTJOYPLUS tristate "SmartJoy PLUS PS2/USB adapter support" depends on HID - ---help--- + help Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box, Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro. @@ -982,20 +983,20 @@ config SMARTJOYPLUS_FF bool "SmartJoy PLUS PS2/USB adapter force feedback support" depends on HID_SMARTJOYPLUS select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to enable force feedback support for it. config HID_TIVO tristate "TiVo Slide Bluetooth remote control support" depends on HID - ---help--- + help Say Y if you have a TiVo Slide Bluetooth remote control. config HID_TOPSEED tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support" depends on HID - ---help--- + help Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic CLLRCMCE remote control. @@ -1004,7 +1005,7 @@ config HID_THINGM depends on HID depends on LEDS_CLASS select HID_LED - ---help--- + help Support for the ThingM blink(1) USB RGB LED. This driver has been merged into the generic hid led driver. Config symbol HID_THINGM just selects HID_LED and will be removed soon. @@ -1012,7 +1013,7 @@ config HID_THINGM config HID_THRUSTMASTER tristate "ThrustMaster devices support" depends on HID - ---help--- + help Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or a THRUSTMASTER Ferrari GT Rumble Wheel. @@ -1020,7 +1021,7 @@ config THRUSTMASTER_FF bool "ThrustMaster devices force feedback support" depends on HID_THRUSTMASTER select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3, a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel. @@ -1028,7 +1029,7 @@ config THRUSTMASTER_FF config HID_UDRAW_PS3 tristate "THQ PS3 uDraw tablet" depends on HID - ---help--- + help Say Y here if you want to use the THQ uDraw gaming tablet for the PS3. @@ -1068,7 +1069,7 @@ config HID_WIIMOTE depends on LEDS_CLASS select POWER_SUPPLY select INPUT_FF_MEMLESS - ---help--- + help Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported devices are the Wii Remote and its extension devices, but also devices based on the Wii Remote like the Wii U Pro Controller or the @@ -1090,7 +1091,7 @@ config HID_WIIMOTE config HID_XINMO tristate "Xin-Mo non-fully compliant devices" depends on HID - ---help--- + help Support for Xin-Mo devices that are not fully compliant with the HID standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here if you have a Xin-Mo Dual Arcade controller. @@ -1098,21 +1099,21 @@ config HID_XINMO config HID_ZEROPLUS tristate "Zeroplus based game controller support" depends on HID - ---help--- + help Say Y here if you have a Zeroplus based game controller. config ZEROPLUS_FF bool "Zeroplus based game controller force feedback support" depends on HID_ZEROPLUS select INPUT_FF_MEMLESS - ---help--- + help Say Y here if you have a Zeroplus based game controller and want to have force feedback support for it. config HID_ZYDACRON tristate "Zydacron remote control support" depends on HID - ---help--- + help Support for Zydacron remote control. config HID_SENSOR_HUB @@ -1120,7 +1121,7 @@ config HID_SENSOR_HUB depends on HID && HAS_IOMEM select MFD_CORE default n - ---help--- + help Support for HID Sensor framework. This creates a MFD instance for a sensor hub and identifies all the sensors connected to it. Each sensor is registered as a MFD cell, so that sensor specific @@ -1133,21 +1134,21 @@ config HID_SENSOR_CUSTOM_SENSOR tristate "HID Sensors hub custom sensor support" depends on HID_SENSOR_HUB default n - ---help--- + help HID Sensor hub specification allows definition of some custom and generic sensors. Unlike other HID sensors, they can't be exported via Linux IIO because of custom fields. This is up to the manufacturer to decide how to interpret these special sensor ids and process in the user space. Currently some manufacturers are using these ids for sensor calibration and debugging other sensors. Manufacturers - should't use these special custom sensor ids to export any of the + shouldn't use these special custom sensor ids to export any of the standard sensors. Select this config option for custom/generic sensor support. config HID_ALPS tristate "Alps HID device support" depends on HID - ---help--- + help Support for Alps I2C HID touchpads and StickPointer. Say Y here if you have a Alps touchpads over i2c-hid or usbhid and want support for its special functionalities. @@ -1156,7 +1157,7 @@ config HID_MCP2221 tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support" depends on USB_HID && I2C depends on GPIOLIB - ---help--- + help Provides I2C and SMBUS host adapter functionality over USB-HID through MCP2221 device. diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 6f1fe7248d81..a9c2de95c5e2 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -25,6 +25,7 @@ #define U1_MOUSE_REPORT_ID 0x01 /* Mouse data ReportID */ #define U1_ABSOLUTE_REPORT_ID 0x03 /* Absolute data ReportID */ +#define U1_ABSOLUTE_REPORT_ID_SECD 0x02 /* FW-PTP Absolute data ReportID */ #define U1_FEATURE_REPORT_ID 0x05 /* Feature ReportID */ #define U1_SP_ABSOLUTE_REPORT_ID 0x06 /* Feature ReportID */ @@ -368,6 +369,7 @@ static int u1_raw_event(struct alps_dev *hdata, u8 *data, int size) case U1_FEATURE_REPORT_ID: break; case U1_ABSOLUTE_REPORT_ID: + case U1_ABSOLUTE_REPORT_ID_SECD: for (i = 0; i < hdata->max_fingers; i++) { u8 *contact = &data[i * 5]; diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index d732d1d10caf..e82f604d33e9 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -51,9 +51,16 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") "(For people who want to keep Windows PC keyboard muscle memory. " "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)"); +static unsigned int swap_fn_leftctrl; +module_param(swap_fn_leftctrl, uint, 0644); +MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " + "(For people who want to keep PC keyboard muscle memory. " + "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); + struct apple_sc { unsigned long quirks; unsigned int fn_on; + unsigned int fn_found; DECLARE_BITMAP(pressed_numlock, KEY_CNT); }; @@ -162,6 +169,11 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = { { } }; +static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { + { KEY_FN, KEY_LEFTCTRL }, + { } +}; + static const struct apple_key_translation *apple_find_translation( const struct apple_key_translation *table, u16 from) { @@ -183,9 +195,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, bool do_translate; u16 code = 0; - if (usage->code == KEY_FN) { + u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN); + + if (usage->code == fn_keycode) { asc->fn_on = !!value; - input_event(input, usage->type, usage->code, value); + input_event(input, usage->type, KEY_FN, value); return 1; } @@ -270,6 +284,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } } + if (swap_fn_leftctrl) { + trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } + } + return 0; } @@ -333,18 +355,26 @@ static void apple_setup_input(struct input_dev *input) for (trans = apple_iso_keyboard; trans->from; trans++) set_bit(trans->to, input->keybit); + + if (swap_fn_leftctrl) { + for (trans = swapped_fn_leftctrl_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + } } static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + struct apple_sc *asc = hid_get_drvdata(hdev); + if (usage->hid == (HID_UP_CUSTOM | 0x0003) || usage->hid == (HID_UP_MSVENDOR | 0x0003) || usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) { /* The fn key on Apple USB keyboards */ set_bit(EV_REP, hi->input->evbit); hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); + asc->fn_found = true; apple_setup_input(hi->input); return 1; } @@ -371,6 +401,19 @@ static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi, return 0; } +static int apple_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { + hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); + asc->quirks = 0; + } + + return 0; +} + static int apple_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -585,6 +628,7 @@ static struct hid_driver apple_driver = { .event = apple_event, .input_mapping = apple_input_mapping, .input_mapped = apple_input_mapped, + .input_configured = apple_input_configured, }; module_hid_driver(apple_driver); diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index e6e4c841fb06..c183caf89d49 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -40,7 +40,9 @@ MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>"); MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define T100_TPAD_INTF 2 +#define MEDION_E1239T_TPAD_INTF 1 +#define E1239T_TP_TOGGLE_REPORT_ID 0x05 #define T100CHI_MOUSE_REPORT_ID 0x06 #define FEATURE_REPORT_ID 0x0d #define INPUT_REPORT_ID 0x5d @@ -77,6 +79,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_G752_KEYBOARD BIT(8) #define QUIRK_T101HA_DOCK BIT(9) #define QUIRK_T90CHI BIT(10) +#define QUIRK_MEDION_E1239T BIT(11) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -102,12 +105,14 @@ struct asus_touchpad_info { int res_y; int contact_size; int max_contacts; + int report_size; }; struct asus_drvdata { unsigned long quirks; struct hid_device *hdev; struct input_dev *input; + struct input_dev *tp_kbd_input; struct asus_kbd_leds *kbd_backlight; const struct asus_touchpad_info *tp; bool enable_backlight; @@ -126,6 +131,7 @@ static const struct asus_touchpad_info asus_i2c_tp = { .max_y = 1758, .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100ta_tp = { @@ -135,6 +141,7 @@ static const struct asus_touchpad_info asus_t100ta_tp = { .res_y = 27, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100ha_tp = { @@ -144,6 +151,7 @@ static const struct asus_touchpad_info asus_t100ha_tp = { .res_y = 29, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t200ta_tp = { @@ -153,6 +161,7 @@ static const struct asus_touchpad_info asus_t200ta_tp = { .res_y = 28, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100chi_tp = { @@ -162,6 +171,17 @@ static const struct asus_touchpad_info asus_t100chi_tp = { .res_y = 29, /* units/mm */ .contact_size = 3, .max_contacts = 4, + .report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */, +}; + +static const struct asus_touchpad_info medion_e1239t_tp = { + .max_x = 2640, + .max_y = 1380, + .res_x = 29, /* units/mm */ + .res_y = 28, /* units/mm */ + .contact_size = 5, + .max_contacts = 5, + .report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */, }; static void asus_report_contact_down(struct asus_drvdata *drvdat, @@ -229,7 +249,7 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) int i, toolType = MT_TOOL_FINGER; u8 *contactData = data + 2; - if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts) + if (size != drvdat->tp->report_size) return 0; for (i = 0; i < drvdat->tp->max_contacts; i++) { @@ -257,6 +277,34 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) return 1; } +static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) +{ + if (size != 3) + return 0; + + /* Handle broken mute key which only sends press events */ + if (!drvdat->tp && + data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) { + input_report_key(drvdat->input, KEY_MUTE, 1); + input_sync(drvdat->input); + input_report_key(drvdat->input, KEY_MUTE, 0); + input_sync(drvdat->input); + return 1; + } + + /* Handle custom touchpad toggle key which only sends press events */ + if (drvdat->tp_kbd_input && + data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) { + input_report_key(drvdat->tp_kbd_input, KEY_F21, 1); + input_sync(drvdat->tp_kbd_input); + input_report_key(drvdat->tp_kbd_input, KEY_F21, 0); + input_sync(drvdat->tp_kbd_input); + return 1; + } + + return 0; +} + static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -281,6 +329,9 @@ static int asus_raw_event(struct hid_device *hdev, if (drvdata->tp && data[0] == INPUT_REPORT_ID) return asus_report_input(drvdata, data, size); + if (drvdata->quirks & QUIRK_MEDION_E1239T) + return asus_e1239t_event(drvdata, data, size); + return 0; } @@ -615,6 +666,21 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) hi->report->id != T100CHI_MOUSE_REPORT_ID) return 0; + /* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */ + if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) { + switch (hi->report->id) { + case E1239T_TP_TOGGLE_REPORT_ID: + input_set_capability(input, EV_KEY, KEY_F21); + input->name = "Asus Touchpad Keys"; + drvdata->tp_kbd_input = input; + return 0; + case INPUT_REPORT_ID: + break; /* Touchpad report, handled below */ + default: + return 0; /* Ignore other reports */ + } + } + if (drvdata->tp) { int ret; @@ -677,24 +743,16 @@ static int asus_input_mapping(struct hid_device *hdev, * This avoids a bunch of non-functional hid_input devices getting * created because of the T100CHI using HID_QUIRK_MULTI_INPUT. */ - if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) { - if (field->application == (HID_UP_GENDESK | 0x0080) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)) - return -1; - /* - * We use the hid_input for the mouse report for the touchpad, - * keep the left button, to avoid the core removing it. - */ - if (field->application == HID_GD_MOUSE && - usage->hid != (HID_UP_BUTTON | 1)) - return -1; - } + if ((drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) && + (field->application == (HID_UP_GENDESK | 0x0080) || + field->application == HID_GD_MOUSE || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) + return -1; /* ASUS-specific keyboard hotkeys */ if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { - set_bit(EV_REP, hi->input->evbit); switch (usage->hid & HID_USAGE) { case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; @@ -737,11 +795,11 @@ static int asus_input_mapping(struct hid_device *hdev, if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) drvdata->enable_backlight = true; + set_bit(EV_REP, hi->input->evbit); return 1; } if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { - set_bit(EV_REP, hi->input->evbit); switch (usage->hid & HID_USAGE) { case 0xff01: asus_map_key_clear(BTN_1); break; case 0xff02: asus_map_key_clear(BTN_2); break; @@ -764,6 +822,7 @@ static int asus_input_mapping(struct hid_device *hdev, return 0; } + set_bit(EV_REP, hi->input->evbit); return 1; } @@ -782,6 +841,16 @@ static int asus_input_mapping(struct hid_device *hdev, } } + /* + * The mute button is broken and only sends press events, we + * deal with this in our raw_event handler, so do not map it. + */ + if ((drvdata->quirks & QUIRK_MEDION_E1239T) && + usage->hid == (HID_UP_CONSUMER | 0xe2)) { + input_set_capability(hi->input, EV_KEY, KEY_MUTE); + return -1; + } + return 0; } @@ -849,7 +918,8 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) if (drvdata->quirks & QUIRK_IS_MULTITOUCH) drvdata->tp = &asus_i2c_tp; - if (drvdata->quirks & QUIRK_T100_KEYBOARD) { + if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && + hid_is_using_ll_driver(hdev, &usb_hid_driver)) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) { @@ -877,6 +947,19 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) drvdata->tp = &asus_t100chi_tp; } + if ((drvdata->quirks & QUIRK_MEDION_E1239T) && + hid_is_using_ll_driver(hdev, &usb_hid_driver)) { + struct usb_host_interface *alt = + to_usb_interface(hdev->dev.parent)->altsetting; + + if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) { + /* For separate input-devs for tp and tp toggle key */ + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING; + drvdata->tp = &medion_e1239t_tp; + } + } + if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; @@ -1056,7 +1139,8 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI }, - + { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T), + QUIRK_MEDION_E1239T }, { } }; MODULE_DEVICE_TABLE(hid, asus_devices); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 359616e3efbb..d2ecc9c45255 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1598,6 +1598,17 @@ static void hid_output_field(const struct hid_device *hid, } /* + * Compute the size of a report. + */ +static size_t hid_compute_report_size(struct hid_report *report) +{ + if (report->size) + return ((report->size - 1) >> 3) + 1; + + return 0; +} + +/* * Create a report. 'data' has to be allocated using * hid_alloc_report_buf() so that it has proper size. */ @@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data) if (report->id > 0) *data++ = report->id; - memset(data, 0, ((report->size - 1) >> 3) + 1); + memset(data, 0, hid_compute_report_size(report)); for (n = 0; n < report->maxfield; n++) hid_output_field(report->device, report->field[n], data); } @@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, csize--; } - rsize = ((report->size - 1) >> 3) + 1; + rsize = hid_compute_report_size(report); if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE) rsize = HID_MAX_BUFFER_SIZE - 1; diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c index 4ff3bc1d25e2..28d671c5e0ca 100644 --- a/drivers/hid/hid-cougar.c +++ b/drivers/hid/hid-cougar.c @@ -321,7 +321,7 @@ static const struct kernel_param_ops cougar_g6_is_space_ops = { }; module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644); -static struct hid_device_id cougar_id_table[] = { +static const struct hid_device_id cougar_id_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index db1b55df0d13..f64517bc33e2 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -11,7 +11,7 @@ * host communicates with the CP2112 via raw HID reports. * * Data Sheet: - * http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf + * https://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf * Programming Interface Specification: * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf */ diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index 45c4f888b7c4..dae193749d44 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c @@ -188,6 +188,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER); if (ret) { hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); + input_free_device(input); return ret; } @@ -198,6 +199,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) { hid_err(hdev, "Failed to register elan input device: %d\n", ret); + input_mt_destroy_slots(input); input_free_device(input); return ret; } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 1c71a1aa76b2..74fc1df6e3c2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -76,12 +76,9 @@ #define USB_VENDOR_ID_ALPS_JP 0x044E #define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B -#define HID_DEVICE_ID_ALPS_U1_DUAL_PTP 0x121F -#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220 #define HID_DEVICE_ID_ALPS_U1 0x1215 #define HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY 0x121E #define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C -#define HID_DEVICE_ID_ALPS_1222 0x1222 #define USB_VENDOR_ID_AMI 0x046b #define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE 0xff10 @@ -281,9 +278,6 @@ #define USB_VENDOR_ID_CIDC 0x1677 -#define I2C_VENDOR_ID_CIRQUE 0x0488 -#define I2C_PRODUCT_ID_CIRQUE_121F 0x121F - #define USB_VENDOR_ID_CJTOUCH 0x24b8 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 @@ -624,6 +618,7 @@ #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2 0xa0c2 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096 0xa096 +#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293 0xa293 #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 @@ -640,6 +635,7 @@ #define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720 0x837a #define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396 #define USB_DEVICE_ID_ITE8595 0x8595 +#define USB_DEVICE_ID_ITE_MEDION_E1239T 0xce50 #define USB_VENDOR_ID_JABRA 0x0b0e #define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 @@ -728,11 +724,13 @@ #define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047 #define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 #define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049 +#define USB_DEVICE_ID_LENOVO_TP10UBKBD 0x6062 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 -#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3 -#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e +#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093 #define USB_VENDOR_ID_LG 0x1fd2 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 @@ -779,6 +777,7 @@ #define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b #define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a +#define USB_DEVICE_ID_LOGITECH_GROUP_AUDIO 0x0882 #define USB_DEVICE_ID_S510_RECEIVER 0xc50c #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 @@ -851,6 +850,7 @@ #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd #define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb +#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS 0x02e0 #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 @@ -1005,6 +1005,8 @@ #define USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO 0x3232 #define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a +#define USB_VENDOR_ID_SAI 0x17dd + #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 #define USB_DEVICE_ID_SAITEK_PS1000 0x0621 @@ -1014,6 +1016,8 @@ #define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa #define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0 #define USB_DEVICE_ID_SAITEK_X52 0x075c +#define USB_DEVICE_ID_SAITEK_X52_2 0x0255 +#define USB_DEVICE_ID_SAITEK_X52_PRO 0x0762 #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 @@ -1157,6 +1161,9 @@ #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882 0x8882 #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883 0x8883 +#define USB_VENDOR_ID_TRUST 0x145f +#define USB_DEVICE_ID_TRUST_PANORA_TABLET 0x0212 + #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 #define USB_DEVICE_ID_ASUS_MD_5110 0x5110 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index dea9cc65bf80..88e19996427e 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -350,13 +350,13 @@ static int hidinput_query_battery_capacity(struct hid_device *dev) u8 *buf; int ret; - buf = kmalloc(2, GFP_KERNEL); + buf = kmalloc(4, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2, + ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4, dev->battery_report_type, HID_REQ_GET_REPORT); - if (ret != 2) { + if (ret < 2) { kfree(buf); return -ENODATA; } @@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } mapped: + /* Mapping failed, bail out */ + if (!bit) + return; + if (device->driver->input_mapped && device->driver->input_mapped(device, hidinput, field, usage, &bit, &max) < 0) { @@ -1560,21 +1564,12 @@ static bool __hidinput_change_resolution_multipliers(struct hid_device *hid, { struct hid_usage *usage; bool update_needed = false; + bool get_report_completed = false; int i, j; if (report->maxfield == 0) return false; - /* - * If we have more than one feature within this report we - * need to fill in the bits from the others before we can - * overwrite the ones for the Resolution Multiplier. - */ - if (report->maxfield > 1) { - hid_hw_request(hid, report, HID_REQ_GET_REPORT); - hid_hw_wait(hid); - } - for (i = 0; i < report->maxfield; i++) { __s32 value = use_logical_max ? report->field[i]->logical_maximum : @@ -1593,6 +1588,25 @@ static bool __hidinput_change_resolution_multipliers(struct hid_device *hid, if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) continue; + /* + * If we have more than one feature within this + * report we need to fill in the bits from the + * others before we can overwrite the ones for the + * Resolution Multiplier. + * + * But if we're not allowed to read from the device, + * we just bail. Such a device should not exist + * anyway. + */ + if (!get_report_completed && report->maxfield > 1) { + if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS) + return update_needed; + + hid_hw_request(hid, report, HID_REQ_GET_REPORT); + hid_hw_wait(hid); + get_report_completed = true; + } + report->field[i]->value[j] = value; update_needed = true; } diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 96fa2a2c2cd3..c6c8e20f3e8d 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -29,29 +29,67 @@ #include <linux/hid.h> #include <linux/input.h> #include <linux/leds.h> +#include <linux/workqueue.h> #include "hid-ids.h" -struct lenovo_drvdata_tpkbd { +struct lenovo_drvdata { + u8 led_report[3]; /* Must be first for proper alignment */ int led_state; + struct mutex led_report_mutex; struct led_classdev led_mute; struct led_classdev led_micmute; + struct work_struct fn_lock_sync_work; + struct hid_device *hdev; int press_to_select; int dragging; int release_to_select; int select_right; int sensitivity; int press_speed; -}; - -struct lenovo_drvdata_cptkbd { u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */ bool fn_lock; - int sensitivity; }; #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) +#define TP10UBKBD_LED_OUTPUT_REPORT 9 + +#define TP10UBKBD_FN_LOCK_LED 0x54 +#define TP10UBKBD_MUTE_LED 0x64 +#define TP10UBKBD_MICMUTE_LED 0x74 + +#define TP10UBKBD_LED_OFF 1 +#define TP10UBKBD_LED_ON 2 + +static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code, + enum led_brightness value) +{ + struct lenovo_drvdata *data = hid_get_drvdata(hdev); + int ret; + + mutex_lock(&data->led_report_mutex); + + data->led_report[0] = TP10UBKBD_LED_OUTPUT_REPORT; + data->led_report[1] = led_code; + data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF; + ret = hid_hw_raw_request(hdev, data->led_report[0], data->led_report, 3, + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + if (ret) + hid_err(hdev, "Set LED output report error: %d\n", ret); + + mutex_unlock(&data->led_report_mutex); +} + +static void lenovo_tp10ubkbd_sync_fn_lock(struct work_struct *work) +{ + struct lenovo_drvdata *data = + container_of(work, struct lenovo_drvdata, fn_lock_sync_work); + + lenovo_led_set_tp10ubkbd(data->hdev, TP10UBKBD_FN_LOCK_LED, + data->fn_lock); +} + static const __u8 lenovo_pro_dock_need_fixup_collection[] = { 0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */ 0x09, 0x01, /* Usage (Vendor Usage 0x01) */ @@ -179,6 +217,44 @@ static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev, return 0; } +static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + /* + * The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for + * a bunch of keys which have no standard consumer page code. + */ + if (usage->hid == 0x000c0001) { + switch (usage->usage_index) { + case 8: /* Fn-Esc: Fn-lock toggle */ + map_key_clear(KEY_FN_ESC); + return 1; + case 9: /* Fn-F4: Mic mute */ + map_key_clear(KEY_MICMUTE); + return 1; + case 10: /* Fn-F7: Control panel */ + map_key_clear(KEY_CONFIG); + return 1; + case 11: /* Fn-F8: Search (magnifier glass) */ + map_key_clear(KEY_SEARCH); + return 1; + case 12: /* Fn-F10: Open My computer (6 boxes) */ + map_key_clear(KEY_FILE); + return 1; + } + } + + /* + * The Ultrabook Keyboard sends a spurious F23 key-press when resuming + * from suspend and it does not actually have a F23 key, ignore it. + */ + if (usage->hid == 0x00070072) + return -1; + + return 0; +} + static int lenovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -199,6 +275,9 @@ static int lenovo_input_mapping(struct hid_device *hdev, case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL: return lenovo_input_mapping_scrollpoint(hdev, hi, field, usage, bit, max); + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field, + usage, bit, max); default: return 0; } @@ -242,7 +321,7 @@ static int lenovo_send_cmd_cptkbd(struct hid_device *hdev, static void lenovo_features_set_cptkbd(struct hid_device *hdev) { int ret; - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); if (ret) @@ -253,23 +332,23 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) hid_err(hdev, "Sensitivity setting failed: %d\n", ret); } -static ssize_t attr_fn_lock_show_cptkbd(struct device *dev, +static ssize_t attr_fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *data = hid_get_drvdata(hdev); - return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock); + return snprintf(buf, PAGE_SIZE, "%u\n", data->fn_lock); } -static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, +static ssize_t attr_fn_lock_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *data = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value)) @@ -277,8 +356,17 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, if (value < 0 || value > 1) return -EINVAL; - cptkbd_data->fn_lock = !!value; - lenovo_features_set_cptkbd(hdev); + data->fn_lock = !!value; + + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_CUSBKBD: + case USB_DEVICE_ID_LENOVO_CBTKBD: + lenovo_features_set_cptkbd(hdev); + break; + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value); + break; + } return count; } @@ -288,7 +376,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->sensitivity); @@ -300,7 +388,7 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) @@ -313,10 +401,10 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, } -static struct device_attribute dev_attr_fn_lock_cptkbd = +static struct device_attribute dev_attr_fn_lock = __ATTR(fn_lock, S_IWUSR | S_IRUGO, - attr_fn_lock_show_cptkbd, - attr_fn_lock_store_cptkbd); + attr_fn_lock_show, + attr_fn_lock_store); static struct device_attribute dev_attr_sensitivity_cptkbd = __ATTR(sensitivity, S_IWUSR | S_IRUGO, @@ -325,7 +413,7 @@ static struct device_attribute dev_attr_sensitivity_cptkbd = static struct attribute *lenovo_attributes_cptkbd[] = { - &dev_attr_fn_lock_cptkbd.attr, + &dev_attr_fn_lock.attr, &dev_attr_sensitivity_cptkbd.attr, NULL }; @@ -354,10 +442,28 @@ static int lenovo_raw_event(struct hid_device *hdev, return 0; } +static int lenovo_event_tp10ubkbd(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct lenovo_drvdata *data = hid_get_drvdata(hdev); + + if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) { + /* + * The user has toggled the Fn-lock state. Toggle our own + * cached value of it and sync our value to the keyboard to + * ensure things are in sync (the sycning should be a no-op). + */ + data->fn_lock = !data->fn_lock; + schedule_work(&data->fn_lock_sync_work); + } + + return 0; +} + static int lenovo_event_cptkbd(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { - struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); /* "wheel" scroll events */ if (usage->type == EV_REL && (usage->code == REL_WHEEL || @@ -396,6 +502,8 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field, case USB_DEVICE_ID_LENOVO_CUSBKBD: case USB_DEVICE_ID_LENOVO_CBTKBD: return lenovo_event_cptkbd(hdev, field, usage, value); + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + return lenovo_event_tp10ubkbd(hdev, field, usage, value); default: return 0; } @@ -404,7 +512,7 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field, static int lenovo_features_set_tpkbd(struct hid_device *hdev) { struct hid_report *report; - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; @@ -425,7 +533,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); } @@ -436,7 +544,7 @@ static ssize_t attr_press_to_select_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value)) @@ -455,7 +563,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); } @@ -466,7 +574,7 @@ static ssize_t attr_dragging_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value)) @@ -485,7 +593,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); } @@ -496,7 +604,7 @@ static ssize_t attr_release_to_select_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value)) @@ -515,7 +623,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); } @@ -526,7 +634,7 @@ static ssize_t attr_select_right_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value)) @@ -545,7 +653,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->sensitivity); @@ -557,7 +665,7 @@ static ssize_t attr_sensitivity_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) @@ -574,7 +682,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev, char *buf) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_speed); @@ -586,7 +694,7 @@ static ssize_t attr_press_speed_store_tpkbd(struct device *dev, size_t count) { struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int value; if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) @@ -642,12 +750,23 @@ static const struct attribute_group lenovo_attr_group_tpkbd = { .attrs = lenovo_attributes_tpkbd, }; -static enum led_brightness lenovo_led_brightness_get_tpkbd( +static void lenovo_led_set_tpkbd(struct hid_device *hdev) +{ + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); + struct hid_report *report; + + report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; + report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; + report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; + hid_hw_request(hdev, report, HID_REQ_SET_REPORT); +} + +static enum led_brightness lenovo_led_brightness_get( struct led_classdev *led_cdev) { struct device *dev = led_cdev->dev->parent; struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); int led_nr = 0; if (led_cdev == &data_pointer->led_micmute) @@ -658,13 +777,13 @@ static enum led_brightness lenovo_led_brightness_get_tpkbd( : LED_OFF; } -static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev, +static void lenovo_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { struct device *dev = led_cdev->dev->parent; struct hid_device *hdev = to_hid_device(dev); - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); - struct hid_report *report; + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); + u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED }; int led_nr = 0; if (led_cdev == &data_pointer->led_micmute) @@ -675,21 +794,58 @@ static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev, else data_pointer->led_state |= 1 << led_nr; - report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; - report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; - report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; - hid_hw_request(hdev, report, HID_REQ_SET_REPORT); + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_TPKBD: + lenovo_led_set_tpkbd(hdev); + break; + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value); + break; + } } -static int lenovo_probe_tpkbd(struct hid_device *hdev) +static int lenovo_register_leds(struct hid_device *hdev) { - struct device *dev = &hdev->dev; - struct lenovo_drvdata_tpkbd *data_pointer; - size_t name_sz = strlen(dev_name(dev)) + 16; - char *name_mute, *name_micmute; - int i; + struct lenovo_drvdata *data = hid_get_drvdata(hdev); + size_t name_sz = strlen(dev_name(&hdev->dev)) + 16; + char *name_mute, *name_micm; int ret; + name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); + name_micm = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); + if (name_mute == NULL || name_micm == NULL) { + hid_err(hdev, "Could not allocate memory for led data\n"); + return -ENOMEM; + } + snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(&hdev->dev)); + snprintf(name_micm, name_sz, "%s:amber:micmute", dev_name(&hdev->dev)); + + data->led_mute.name = name_mute; + data->led_mute.brightness_get = lenovo_led_brightness_get; + data->led_mute.brightness_set = lenovo_led_brightness_set; + data->led_mute.dev = &hdev->dev; + ret = led_classdev_register(&hdev->dev, &data->led_mute); + if (ret < 0) + return ret; + + data->led_micmute.name = name_micm; + data->led_micmute.brightness_get = lenovo_led_brightness_get; + data->led_micmute.brightness_set = lenovo_led_brightness_set; + data->led_micmute.dev = &hdev->dev; + ret = led_classdev_register(&hdev->dev, &data->led_micmute); + if (ret < 0) { + led_classdev_unregister(&data->led_mute); + return ret; + } + + return 0; +} + +static int lenovo_probe_tpkbd(struct hid_device *hdev) +{ + struct lenovo_drvdata *data_pointer; + int i, ret; + /* * Only register extra settings against subdevice where input_mapping * set drvdata to 1, i.e. the trackpoint. @@ -712,7 +868,7 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) hid_warn(hdev, "Could not create sysfs group: %d\n", ret); data_pointer = devm_kzalloc(&hdev->dev, - sizeof(struct lenovo_drvdata_tpkbd), + sizeof(struct lenovo_drvdata), GFP_KERNEL); if (data_pointer == NULL) { hid_err(hdev, "Could not allocate memory for driver data\n"); @@ -724,37 +880,11 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) data_pointer->sensitivity = 0xa0; data_pointer->press_speed = 0x38; - name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); - name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); - if (name_mute == NULL || name_micmute == NULL) { - hid_err(hdev, "Could not allocate memory for led data\n"); - ret = -ENOMEM; - goto err; - } - snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); - snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); - hid_set_drvdata(hdev, data_pointer); - data_pointer->led_mute.name = name_mute; - data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd; - data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd; - data_pointer->led_mute.dev = dev; - ret = led_classdev_register(dev, &data_pointer->led_mute); - if (ret < 0) - goto err; - - data_pointer->led_micmute.name = name_micmute; - data_pointer->led_micmute.brightness_get = - lenovo_led_brightness_get_tpkbd; - data_pointer->led_micmute.brightness_set = - lenovo_led_brightness_set_tpkbd; - data_pointer->led_micmute.dev = dev; - ret = led_classdev_register(dev, &data_pointer->led_micmute); - if (ret < 0) { - led_classdev_unregister(&data_pointer->led_mute); + ret = lenovo_register_leds(hdev); + if (ret) goto err; - } lenovo_features_set_tpkbd(hdev); @@ -767,7 +897,7 @@ err: static int lenovo_probe_cptkbd(struct hid_device *hdev) { int ret; - struct lenovo_drvdata_cptkbd *cptkbd_data; + struct lenovo_drvdata *cptkbd_data; /* All the custom action happens on the USBMOUSE device for USB */ if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD @@ -811,6 +941,57 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) return 0; } +static struct attribute *lenovo_attributes_tp10ubkbd[] = { + &dev_attr_fn_lock.attr, + NULL +}; + +static const struct attribute_group lenovo_attr_group_tp10ubkbd = { + .attrs = lenovo_attributes_tp10ubkbd, +}; + +static int lenovo_probe_tp10ubkbd(struct hid_device *hdev) +{ + struct lenovo_drvdata *data; + int ret; + + /* All the custom action happens on the USBMOUSE device for USB */ + if (hdev->type != HID_TYPE_USBMOUSE) + return 0; + + data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + mutex_init(&data->led_report_mutex); + INIT_WORK(&data->fn_lock_sync_work, lenovo_tp10ubkbd_sync_fn_lock); + data->hdev = hdev; + + hid_set_drvdata(hdev, data); + + /* + * The Thinkpad 10 ultrabook USB kbd dock's Fn-lock defaults to on. + * We cannot read the state, only set it, so we force it to on here + * (which should be a no-op) to make sure that our state matches the + * keyboard's FN-lock state. This is the same as what Windows does. + */ + data->fn_lock = true; + lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock); + + ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd); + if (ret) + return ret; + + ret = lenovo_register_leds(hdev); + if (ret) + goto err; + + return 0; +err: + sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd); + return ret; +} + static int lenovo_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -836,6 +1017,9 @@ static int lenovo_probe(struct hid_device *hdev, case USB_DEVICE_ID_LENOVO_CBTKBD: ret = lenovo_probe_cptkbd(hdev); break; + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + ret = lenovo_probe_tp10ubkbd(hdev); + break; default: ret = 0; break; @@ -852,7 +1036,7 @@ err: static void lenovo_remove_tpkbd(struct hid_device *hdev) { - struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev); + struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev); /* * Only the trackpoint half of the keyboard has drvdata and stuff that @@ -874,6 +1058,20 @@ static void lenovo_remove_cptkbd(struct hid_device *hdev) &lenovo_attr_group_cptkbd); } +static void lenovo_remove_tp10ubkbd(struct hid_device *hdev) +{ + struct lenovo_drvdata *data = hid_get_drvdata(hdev); + + if (data == NULL) + return; + + led_classdev_unregister(&data->led_micmute); + led_classdev_unregister(&data->led_mute); + + sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tp10ubkbd); + cancel_work_sync(&data->fn_lock_sync_work); +} + static void lenovo_remove(struct hid_device *hdev) { switch (hdev->product) { @@ -884,6 +1082,9 @@ static void lenovo_remove(struct hid_device *hdev) case USB_DEVICE_ID_LENOVO_CBTKBD: lenovo_remove_cptkbd(hdev); break; + case USB_DEVICE_ID_LENOVO_TP10UBKBD: + lenovo_remove_tp10ubkbd(hdev); + break; } hid_hw_stop(hdev); @@ -920,6 +1121,7 @@ static const struct hid_device_id lenovo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) }, { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TP10UBKBD) }, { } }; diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c index ef0cbcd7540d..fcaf8466e627 100644 --- a/drivers/hid/hid-lg-g15.c +++ b/drivers/hid/hid-lg-g15.c @@ -680,7 +680,7 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i) * but it does have a separate power-on (reset) value. */ g15->leds[i].cdev.name = "g15::power_on_backlight_val"; - /* fall through */ + fallthrough; case LG_G15_KBD_BRIGHTNESS: g15->leds[i].cdev.brightness_set_blocking = lg_g510_kbd_led_set; diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index ed9b1c1f460d..38ee25a813b9 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * HID driver for Logitech Unifying receivers + * HID driver for Logitech receivers * * Copyright (c) 2011 Logitech */ @@ -701,7 +701,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, type_str, dj_hiddev->product); } else { snprintf(dj_hiddev->name, sizeof(dj_hiddev->name), - "Logitech Unifying Device. Wireless PID:%04x", + "Logitech Wireless Device PID:%04x", dj_hiddev->product); } @@ -844,7 +844,7 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, workitem.type = WORKITEM_TYPE_EMPTY; break; } - /* fall-through */ + fallthrough; case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: workitem.quad_id_msb = dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB]; @@ -1153,7 +1153,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) if (!dj_report) return -ENOMEM; dj_report->report_id = REPORT_ID_DJ_SHORT; - dj_report->device_index = 0xFF; + dj_report->device_index = HIDPP_RECEIVER_INDEX; dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; retval = logi_dj_recv_send_report(djrcv_dev, dj_report); kfree(dj_report); @@ -1175,7 +1175,7 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, if (djrcv_dev->type == recvr_type_dj) { dj_report->report_id = REPORT_ID_DJ_SHORT; - dj_report->device_index = 0xFF; + dj_report->device_index = HIDPP_RECEIVER_INDEX; dj_report->report_type = REPORT_TYPE_CMD_SWITCH; dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F; dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = @@ -1204,7 +1204,7 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, memset(buf, 0, HIDPP_REPORT_SHORT_LENGTH); buf[0] = REPORT_ID_HIDPP_SHORT; - buf[1] = 0xFF; + buf[1] = HIDPP_RECEIVER_INDEX; buf[2] = 0x80; buf[3] = 0x00; buf[4] = 0x00; diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 094f4f1b6555..b8b53dc95e86 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * HIDPP protocol for Logitech Unifying receivers + * HIDPP protocol for Logitech receivers * * Copyright (c) 2011 Logitech (c) * Copyright (c) 2012-2013 Google (c) @@ -3146,7 +3146,7 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp) multiplier = 1; hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; - hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier); + hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier); return 0; } diff --git a/drivers/hid/hid-macally.c b/drivers/hid/hid-macally.c index 9a4fc7dffb14..aea46e522008 100644 --- a/drivers/hid/hid-macally.c +++ b/drivers/hid/hid-macally.c @@ -29,7 +29,7 @@ static __u8 *macally_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } -static struct hid_device_id macally_id_table[] = { +static const struct hid_device_id macally_id_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD) }, { } diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 34138667f8af..abd86903875f 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -535,6 +535,12 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(MSC_RAW, input->mscbit); } + /* + * hid-input may mark device as using autorepeat, but neither + * the trackpad, nor the mouse actually want it. + */ + __clear_bit(EV_REP, input->evbit); + return 0; } diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index d958475f8c81..0d27ccb55dd9 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -4,7 +4,7 @@ * * Copyright (c) 2020, Rishi Gupta <gupt21@gmail.com> * - * Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20005565B.pdf + * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/20005565B.pdf */ #include <linux/module.h> @@ -15,6 +15,7 @@ #include <linux/hid.h> #include <linux/hidraw.h> #include <linux/i2c.h> +#include <linux/gpio/driver.h> #include "hid-ids.h" /* Commands codes in a raw output report */ @@ -27,6 +28,8 @@ enum { MCP2221_I2C_PARAM_OR_STATUS = 0x10, MCP2221_I2C_SET_SPEED = 0x20, MCP2221_I2C_CANCEL = 0x10, + MCP2221_GPIO_SET = 0x50, + MCP2221_GPIO_GET = 0x51, }; /* Response codes in a raw input report */ @@ -42,6 +45,8 @@ enum { MCP2221_I2C_WRADDRL_SEND = 0x21, MCP2221_I2C_ADDR_NACK = 0x25, MCP2221_I2C_READ_COMPL = 0x55, + MCP2221_ALT_F_NOT_GPIOV = 0xEE, + MCP2221_ALT_F_NOT_GPIOD = 0xEF, }; /* @@ -59,6 +64,9 @@ struct mcp2221 { int rxbuf_idx; int status; u8 cur_i2c_clk_div; + struct gpio_chip *gc; + u8 gp_idx; + u8 gpio_dir; }; /* @@ -526,6 +534,110 @@ static const struct i2c_algorithm mcp_i2c_algo = { .functionality = mcp_i2c_func, }; +static int mcp_gpio_get(struct gpio_chip *gc, + unsigned int offset) +{ + int ret; + struct mcp2221 *mcp = gpiochip_get_data(gc); + + mcp->txbuf[0] = MCP2221_GPIO_GET; + + mcp->gp_idx = (offset + 1) * 2; + + mutex_lock(&mcp->lock); + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); + mutex_unlock(&mcp->lock); + + return ret; +} + +static void mcp_gpio_set(struct gpio_chip *gc, + unsigned int offset, int value) +{ + struct mcp2221 *mcp = gpiochip_get_data(gc); + + memset(mcp->txbuf, 0, 18); + mcp->txbuf[0] = MCP2221_GPIO_SET; + + mcp->gp_idx = ((offset + 1) * 4) - 1; + + mcp->txbuf[mcp->gp_idx - 1] = 1; + mcp->txbuf[mcp->gp_idx] = !!value; + + mutex_lock(&mcp->lock); + mcp_send_data_req_status(mcp, mcp->txbuf, 18); + mutex_unlock(&mcp->lock); +} + +static int mcp_gpio_dir_set(struct mcp2221 *mcp, + unsigned int offset, u8 val) +{ + memset(mcp->txbuf, 0, 18); + mcp->txbuf[0] = MCP2221_GPIO_SET; + + mcp->gp_idx = (offset + 1) * 5; + + mcp->txbuf[mcp->gp_idx - 1] = 1; + mcp->txbuf[mcp->gp_idx] = val; + + return mcp_send_data_req_status(mcp, mcp->txbuf, 18); +} + +static int mcp_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + int ret; + struct mcp2221 *mcp = gpiochip_get_data(gc); + + mutex_lock(&mcp->lock); + ret = mcp_gpio_dir_set(mcp, offset, 0); + mutex_unlock(&mcp->lock); + + return ret; +} + +static int mcp_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + int ret; + struct mcp2221 *mcp = gpiochip_get_data(gc); + + mutex_lock(&mcp->lock); + ret = mcp_gpio_dir_set(mcp, offset, 1); + mutex_unlock(&mcp->lock); + + /* Can't configure as output, bailout early */ + if (ret) + return ret; + + mcp_gpio_set(gc, offset, value); + + return 0; +} + +static int mcp_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + int ret; + struct mcp2221 *mcp = gpiochip_get_data(gc); + + mcp->txbuf[0] = MCP2221_GPIO_GET; + + mcp->gp_idx = (offset + 1) * 2; + + mutex_lock(&mcp->lock); + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); + mutex_unlock(&mcp->lock); + + if (ret) + return ret; + + if (mcp->gpio_dir) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + /* Gives current state of i2c engine inside mcp2221 */ static int mcp_get_i2c_eng_state(struct mcp2221 *mcp, u8 *data, u8 idx) @@ -638,6 +750,39 @@ static int mcp2221_raw_event(struct hid_device *hdev, complete(&mcp->wait_in_report); break; + case MCP2221_GPIO_GET: + switch (data[1]) { + case MCP2221_SUCCESS: + if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) || + (data[mcp->gp_idx + 1] == MCP2221_ALT_F_NOT_GPIOD)) { + mcp->status = -ENOENT; + } else { + mcp->status = !!data[mcp->gp_idx]; + mcp->gpio_dir = !!data[mcp->gp_idx + 1]; + } + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + + case MCP2221_GPIO_SET: + switch (data[1]) { + case MCP2221_SUCCESS: + if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) || + (data[mcp->gp_idx - 1] == MCP2221_ALT_F_NOT_GPIOV)) { + mcp->status = -ENOENT; + } else { + mcp->status = 0; + } + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + default: mcp->status = -EIO; complete(&mcp->wait_in_report); @@ -702,8 +847,32 @@ static int mcp2221_probe(struct hid_device *hdev, } i2c_set_adapdata(&mcp->adapter, mcp); + /* Setup GPIO chip */ + mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL); + if (!mcp->gc) { + ret = -ENOMEM; + goto err_gc; + } + + mcp->gc->label = "mcp2221_gpio"; + mcp->gc->direction_input = mcp_gpio_direction_input; + mcp->gc->direction_output = mcp_gpio_direction_output; + mcp->gc->get_direction = mcp_gpio_get_direction; + mcp->gc->set = mcp_gpio_set; + mcp->gc->get = mcp_gpio_get; + mcp->gc->ngpio = 4; + mcp->gc->base = -1; + mcp->gc->can_sleep = 1; + mcp->gc->parent = &hdev->dev; + + ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp); + if (ret) + goto err_gc; + return 0; +err_gc: + i2c_del_adapter(&mcp->adapter); err_i2c: hid_hw_close(mcp->hdev); err_hstop: diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 2d8b589201a4..071fd093a5f4 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -163,16 +163,13 @@ static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field, { switch (usage->hid & HID_USAGE_PAGE) { case 0xff070000: - /* fall-through */ case HID_UP_DIGITIZER: /* ignore those axis */ return -1; case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: - /* fall-through */ case HID_GD_Y: - /* fall-through */ case HID_GD_RFKILL_BTN: /* ignore those axis */ return -1; @@ -451,6 +448,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_SURFACE_DIAL }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER), .driver_data = MS_QUIRK_FF }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS), + .driver_data = MS_QUIRK_FF }, { } }; MODULE_DEVICE_TABLE(hid, ms_devices); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 241740222199..e3152155c4b8 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -69,6 +69,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) #define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) +#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -188,7 +189,8 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); /* reserved 0x0011 */ #define MT_CLS_WIN_8 0x0012 #define MT_CLS_EXPORT_ALL_INPUTS 0x0013 -#define MT_CLS_WIN_8_DUAL 0x0014 +/* reserved 0x0014 */ +#define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -272,12 +274,14 @@ static const struct mt_class mt_classes[] = { .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, .export_all_inputs = true }, - { .name = MT_CLS_WIN_8_DUAL, + { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_WIN8_PTP_BUTTONS, + MT_QUIRK_STICKY_FINGERS | + MT_QUIRK_WIN8_PTP_BUTTONS | + MT_QUIRK_FORCE_MULTI_INPUT, .export_all_inputs = true }, /* @@ -754,8 +758,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, MT_STORE_FIELD(inrange_state); return 1; case HID_DG_CONFIDENCE: - if ((cls->name == MT_CLS_WIN_8 || - cls->name == MT_CLS_WIN_8_DUAL) && + if (cls->name == MT_CLS_WIN_8 && (field->application == HID_DG_TOUCHPAD || field->application == HID_DG_TOUCHSCREEN)) app->quirks |= MT_QUIRK_CONFIDENCE; @@ -853,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, code = BTN_0 + ((usage->hid - 1) & HID_USAGE); hid_map_usage(hi, usage, bit, max, EV_KEY, code); + if (!*bit) + return -1; input_set_capability(hi->input, EV_KEY, code); return 1; @@ -1712,6 +1717,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (id->group != HID_GROUP_MULTITOUCH_WIN_8) hdev->quirks |= HID_QUIRK_MULTI_INPUT; + if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) { + hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP; + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + } + timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); @@ -1784,32 +1794,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M3266) }, - /* Alps devices */ - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, - USB_VENDOR_ID_ALPS_JP, - HID_DEVICE_ID_ALPS_U1_DUAL_PTP) }, - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, - USB_VENDOR_ID_ALPS_JP, - HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) }, - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, - USB_VENDOR_ID_ALPS_JP, - HID_DEVICE_ID_ALPS_1222) }, - - /* Lenovo X1 TAB Gen 2 */ - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, - USB_VENDOR_ID_LENOVO, - USB_DEVICE_ID_LENOVO_X1_TAB) }, - - /* Lenovo X1 TAB Gen 3 */ - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, - USB_VENDOR_ID_LENOVO, - USB_DEVICE_ID_LENOVO_X1_TAB3) }, - /* Anton devices */ { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, MT_USB_DEVICE(USB_VENDOR_ID_ANTON, @@ -1844,12 +1828,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, - /* Cirque devices */ - { .driver_data = MT_CLS_WIN_8_DUAL, - HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, - I2C_VENDOR_ID_CIRQUE, - I2C_PRODUCT_ID_CIRQUE_121F) }, - /* CJTouch panels */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, @@ -1924,6 +1902,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) }, + /* Elan devices */ + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_ELAN, 0x313a) }, + /* Elitegroup panel */ { .driver_data = MT_CLS_SERIAL, MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP, @@ -2054,6 +2037,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, + /* Synaptics devices */ + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_SYNAPTICS, 0xce08) }, + /* TopSeed panels */ { .driver_data = MT_CLS_TOPSEED, MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index e4cb543de0cd..7a2be0205dfd 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -88,6 +88,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A293), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, @@ -104,6 +105,9 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, @@ -146,6 +150,8 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, @@ -168,6 +174,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET), HID_QUIRK_MULTI_INPUT | HID_QUIRK_HIDINPUT_FORCE }, { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT }, @@ -177,6 +184,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET }, { 0 } }; @@ -831,6 +839,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAI, USB_DEVICE_ID_CYPRESS_HIDCOM) }, #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB) { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) }, diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index acac09ba7dd5..311eee599ce9 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -428,7 +428,6 @@ static void rmi_report(struct hid_device *hid, struct hid_report *report) switch (report->id) { case RMI_READ_DATA_REPORT_ID: - /* fall-through */ case RMI_ATTN_REPORT_ID: return; } diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 1a6e600197d0..2ff4c8e366ff 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -780,7 +780,7 @@ static void kone_keep_values_up_to_date(struct kone_device *kone, case kone_mouse_event_switch_profile: kone->actual_dpi = kone->profiles[event->value - 1]. startup_dpi; - /* fall through */ + fallthrough; case kone_mouse_event_osd_profile: kone->actual_profile = event->value; break; diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4c6ed6ef31f1..2f073f536070 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -867,6 +867,23 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); + /* + * Some knock-off USB dongles incorrectly report their button count + * as 13 instead of 16 causing three non-functional buttons. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize >= 45 && + /* Report Count (13) */ + rdesc[23] == 0x95 && rdesc[24] == 0x0D && + /* Usage Maximum (13) */ + rdesc[37] == 0x29 && rdesc[38] == 0x0D && + /* Report Count (3) */ + rdesc[43] == 0x95 && rdesc[44] == 0x03) { + hid_info(hdev, "Fixing up USB dongle report descriptor\n"); + rdesc[24] = 0x10; + rdesc[38] = 0x10; + rdesc[44] = 0x00; + } + return rdesc; } diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index 6286204d4c56..a3b151b29bd7 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -526,7 +526,8 @@ static int steam_register(struct steam_device *steam) steam_battery_register(steam); mutex_lock(&steam_devices_lock); - list_add(&steam->list, &steam_devices); + if (list_empty(&steam->list)) + list_add(&steam->list, &steam_devices); mutex_unlock(&steam_devices_lock); } @@ -552,7 +553,7 @@ static void steam_unregister(struct steam_device *steam) hid_info(steam->hdev, "Steam Controller '%s' disconnected", steam->serial_no); mutex_lock(&steam_devices_lock); - list_del(&steam->list); + list_del_init(&steam->list); mutex_unlock(&steam_devices_lock); steam->serial_no[0] = 0; } @@ -738,6 +739,7 @@ static int steam_probe(struct hid_device *hdev, mutex_init(&steam->mutex); steam->quirks = id->driver_data; INIT_WORK(&steam->work_connect, steam_work_connect_cb); + INIT_LIST_HEAD(&steam->list); steam->client_hdev = steam_create_client_hid(hdev); if (IS_ERR(steam->client_hdev)) { diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 78a364ae2f68..7d20d1fcf8d2 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -974,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params, } break; } - /* FALL THROUGH */ + fallthrough; case VID_PID(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_HUION, diff --git a/drivers/hid/hid-udraw-ps3.c b/drivers/hid/hid-udraw-ps3.c index b0fbd11aa0fc..b2e17ef2ea27 100644 --- a/drivers/hid/hid-udraw-ps3.c +++ b/drivers/hid/hid-udraw-ps3.c @@ -16,7 +16,7 @@ MODULE_LICENSE("GPL"); /* * Protocol information from: - * http://brandonw.net/udraw/ + * https://brandonw.net/udraw/ * and the source code of: * https://vvvv.org/contribution/udraw-hid */ diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 92874dbe4d4a..e484c3618dec 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1672,7 +1672,6 @@ static ssize_t wiimote_ext_show(struct device *dev, case WIIMOTE_EXT_GUITAR: return sprintf(buf, "guitar\n"); case WIIMOTE_EXT_UNKNOWN: - /* fallthrough */ default: return sprintf(buf, "unknown\n"); } @@ -1722,7 +1721,6 @@ static ssize_t wiimote_dev_show(struct device *dev, case WIIMOTE_DEV_PENDING: return sprintf(buf, "pending\n"); case WIIMOTE_DEV_UNKNOWN: - /* fallthrough */ default: return sprintf(buf, "unknown\n"); } @@ -1870,6 +1868,11 @@ static const struct hid_device_id wiimote_hid_devices[] = { USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { } }; + +bool wiimote_dpad_as_analog = false; +module_param_named(dpad_as_analog, wiimote_dpad_as_analog, bool, 0644); +MODULE_PARM_DESC(dpad_as_analog, "Use D-Pad as main analog input"); + MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); static struct hid_driver wiimote_hid_driver = { diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c index 2c3925357857..213c58bf2495 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c @@ -1088,12 +1088,28 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext) * is the same as before. */ + static const s8 digital_to_analog[3] = {0x20, 0, -0x20}; + if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { - lx = ext[0] & 0x3e; - ly = ext[1] & 0x3e; + if (wiimote_dpad_as_analog) { + lx = digital_to_analog[1 - !(ext[4] & 0x80) + + !(ext[1] & 0x01)]; + ly = digital_to_analog[1 - !(ext[4] & 0x40) + + !(ext[0] & 0x01)]; + } else { + lx = (ext[0] & 0x3e) - 0x20; + ly = (ext[1] & 0x3e) - 0x20; + } } else { - lx = ext[0] & 0x3f; - ly = ext[1] & 0x3f; + if (wiimote_dpad_as_analog) { + lx = digital_to_analog[1 - !(ext[4] & 0x80) + + !(ext[5] & 0x02)]; + ly = digital_to_analog[1 - !(ext[4] & 0x40) + + !(ext[5] & 0x01)]; + } else { + lx = (ext[0] & 0x3f) - 0x20; + ly = (ext[1] & 0x3f) - 0x20; + } } rx = (ext[0] >> 3) & 0x18; @@ -1110,20 +1126,14 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext) rt <<= 1; lt <<= 1; - input_report_abs(wdata->extension.input, ABS_HAT1X, lx - 0x20); - input_report_abs(wdata->extension.input, ABS_HAT1Y, ly - 0x20); + input_report_abs(wdata->extension.input, ABS_HAT1X, lx); + input_report_abs(wdata->extension.input, ABS_HAT1Y, ly); input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20); input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20); input_report_abs(wdata->extension.input, ABS_HAT3X, rt); input_report_abs(wdata->extension.input, ABS_HAT3Y, lt); input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT], - !(ext[4] & 0x80)); - input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN], - !(ext[4] & 0x40)); - input_report_key(wdata->extension.input, wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT], !(ext[4] & 0x20)); input_report_key(wdata->extension.input, @@ -1157,20 +1167,29 @@ static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext) wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR], !(ext[5] & 0x04)); - if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { - input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], - !(ext[1] & 0x01)); - input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], - !(ext[0] & 0x01)); - } else { + if (!wiimote_dpad_as_analog) { input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], - !(ext[5] & 0x02)); + wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT], + !(ext[4] & 0x80)); input_report_key(wdata->extension.input, - wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], - !(ext[5] & 0x01)); + wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN], + !(ext[4] & 0x40)); + + if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { + input_report_key(wdata->extension.input, + wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], + !(ext[1] & 0x01)); + input_report_key(wdata->extension.input, + wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], + !(ext[0] & 0x01)); + } else { + input_report_key(wdata->extension.input, + wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT], + !(ext[5] & 0x02)); + input_report_key(wdata->extension.input, + wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP], + !(ext[5] & 0x01)); + } } input_sync(wdata->extension.input); diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index b2a26a0a8f12..ad4ff837f43e 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h @@ -162,6 +162,8 @@ struct wiimote_data { struct work_struct init_worker; }; +extern bool wiimote_dpad_as_analog; + /* wiimote modules */ enum wiimod_module { diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig index 0e2ae47f38a7..c4e5dfeab2bd 100644 --- a/drivers/hid/i2c-hid/Kconfig +++ b/drivers/hid/i2c-hid/Kconfig @@ -7,7 +7,7 @@ config I2C_HID default n depends on I2C && INPUT select HID - ---help--- + help Say Y here if you use a keyboard, a touchpad, a touchscreen, or any other HID based devices which is connected to your computer via I2C. diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 294c84e136d7..dbd04492825d 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -420,6 +420,19 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) dev_err(&client->dev, "failed to change power setting.\n"); set_pwr_exit: + + /* + * The HID over I2C specification states that if a DEVICE needs time + * after the PWR_ON request, it should utilise CLOCK stretching. + * However, it has been observered that the Windows driver provides a + * 1ms sleep between the PWR_ON and RESET requests. + * According to Goodix Windows even waits 60 ms after (other?) + * PWR_ON requests. Testing has confirmed that several devices + * will not work properly without a delay after a PWR_ON request. + */ + if (!ret && power_state == I2C_HID_PWR_ON) + msleep(60); + return ret; } @@ -441,15 +454,6 @@ static int i2c_hid_hwreset(struct i2c_client *client) if (ret) goto out_unlock; - /* - * The HID over I2C specification states that if a DEVICE needs time - * after the PWR_ON request, it should utilise CLOCK stretching. - * However, it has been observered that the Windows driver provides a - * 1ms sleep between the PWR_ON and RESET requests and that some devices - * rely on this. - */ - usleep_range(1000, 5000); - i2c_hid_dbg(ihid, "resetting...\n"); ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index a66f08041a1a..35f3bfc3e6f5 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -374,6 +374,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { .driver_data = (void *)&sipodev_desc }, { + .ident = "Mediacom FlexBook edge 13", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook_edge13-M-FBE13"), + }, + .driver_data = (void *)&sipodev_desc + }, + { .ident = "Odys Winbook 13", .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"), @@ -389,6 +397,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { }, .driver_data = (void *)&sipodev_desc }, + { + .ident = "Schneider SCL142ALM", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SCHNEIDER"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SCL142ALM"), + }, + .driver_data = (void *)&sipodev_desc + }, { } /* Terminate list */ }; diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index f491d8b4e24c..c6d48a8648b7 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -106,6 +106,11 @@ static inline bool ish_should_enter_d0i3(struct pci_dev *pdev) return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID; } +static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) +{ + return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID; +} + /** * ish_probe() - PCI driver probe callback * @pdev: pci device @@ -215,9 +220,7 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) struct ishtp_device *dev = pci_get_drvdata(pdev); int ret; - /* Check the NO_D3 flag to distinguish the resume paths */ - if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) { - pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3; + if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag) { disable_irq_wake(pdev->irq); ishtp_send_resume(dev); @@ -281,8 +284,11 @@ static int __maybe_unused ish_suspend(struct device *device) */ ish_disable_dma(dev); } else { - /* Set the NO_D3 flag, the ISH would enter D0i3 */ - pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; + /* + * Save state so PCI core will keep the device at D0, + * the ISH would enter D0i3 + */ + pci_save_state(pdev); enable_irq_wake(pdev->irq); } diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index aa2dbed30fc3..6cf59fd26ad7 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -480,6 +480,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data, sizeof(ldr_xfer_query_resp)); if (rv < 0) { client_data->flag_retry = true; + *fw_info = (struct shim_fw_info){}; return rv; } @@ -489,6 +490,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data, "data size %d is not equal to size of loader_xfer_query_response %zu\n", rv, sizeof(struct loader_xfer_query_response)); client_data->flag_retry = true; + *fw_info = (struct shim_fw_info){}; return -EMSGSIZE; } diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index b5f3a3c4149e..dcf3a235870f 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -7,7 +7,7 @@ config USB_HID default y depends on USB && INPUT select HID - ---help--- + help Say Y here if you want to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices to your computer via USB, as well as Uninterruptible Power Supply @@ -51,7 +51,7 @@ menu "USB HID Boot Protocol drivers" config USB_KBD tristate "USB HIDBP Keyboard (simple Boot) support" depends on USB && INPUT - ---help--- + help Say Y here only if you are absolutely sure that you don't want to use the generic HID driver for your USB keyboard and prefer to use the keyboard in its limited Boot Protocol mode instead. @@ -67,7 +67,7 @@ config USB_KBD config USB_MOUSE tristate "USB HIDBP Mouse (simple Boot) support" depends on USB && INPUT - ---help--- + help Say Y here only if you are absolutely sure that you don't want to use the generic HID driver for your USB mouse and prefer to use the mouse in its limited Boot Protocol mode instead. diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 17a638f15082..17a29ee0ac6c 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1667,7 +1667,7 @@ struct usb_interface *usbhid_find_interface(int minor) static int __init hid_init(void) { - int retval = -ENOMEM; + int retval; retval = hid_quirks_init(quirks_param, BUS_USB, MAX_USBHID_BOOT_QUIRKS); if (retval) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 4140dea693e9..45e0b1c75cb1 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -519,12 +519,16 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, switch (cmd) { case HIDIOCGUSAGE: + if (uref->usage_index >= field->report_count) + goto inval; uref->value = field->value[uref->usage_index]; if (copy_to_user(user_arg, uref, sizeof(*uref))) goto fault; goto goodreturn; case HIDIOCSUSAGE: + if (uref->usage_index >= field->report_count) + goto inval; field->value[uref->usage_index] = uref->value; goto goodreturn; @@ -781,7 +785,6 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case HIDIOCGUCODE: - /* fall through */ case HIDIOCGUSAGE: case HIDIOCSUSAGE: case HIDIOCGUSAGES: diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 1c96809b51c9..83dfec327c42 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -341,7 +341,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) case 2: /* Mouse with wheel */ input_report_key(input, BTN_MIDDLE, data[1] & 0x04); - /* fall through */ + fallthrough; case 3: /* Mouse without wheel */ wacom->tool[0] = BTN_TOOL_MOUSE; @@ -1201,7 +1201,7 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) case 0x04: wacom_intuos_bt_process_data(wacom, data + i); i += 10; - /* fall through */ + fallthrough; case 0x03: wacom_intuos_bt_process_data(wacom, data + i); i += 10; @@ -2148,7 +2148,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field for (i = 0; i < wacom->led.count; i++) wacom_update_led(wacom, features->numbered_buttons, value, i); - /* fall through*/ + fallthrough; default: do_report = true; break; @@ -3602,14 +3602,14 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, switch (features->type) { case GRAPHIRE_BT: __clear_bit(ABS_MISC, input_dev->absbit); - /* fall through */ + fallthrough; case WACOM_MO: case WACOM_G4: input_set_abs_params(input_dev, ABS_DISTANCE, 0, features->distance_max, features->distance_fuzz, 0); - /* fall through */ + fallthrough; case GRAPHIRE: input_set_capability(input_dev, EV_REL, REL_WHEEL); @@ -3649,7 +3649,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case INTUOS4S: input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_abs_set_res(input_dev, ABS_Z, 287); - /* fall through */ + fallthrough; case INTUOS: wacom_setup_intuos(wacom_wac); @@ -3682,7 +3682,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case TABLETPC: case TABLETPCE: __clear_bit(ABS_MISC, input_dev->absbit); - /* fall through */ + fallthrough; case DTUS: case DTUSX: @@ -3696,7 +3696,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case PTU: __set_bit(BTN_STYLUS2, input_dev->keybit); - /* fall through */ + fallthrough; case PENPARTNER: __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -3799,7 +3799,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40); - /* fall through */ + fallthrough; case INTUOS5: case INTUOS5L: @@ -3817,7 +3817,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); - /* fall through */ + fallthrough; case WACOM_27QHDT: if (wacom_wac->shared->touch->product == 0x32C || @@ -3826,14 +3826,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, __set_bit(SW_MUTE_DEVICE, input_dev->swbit); wacom_wac->shared->has_mute_touch_switch = true; } - /* fall through */ + fallthrough; case MTSCREEN: case MTTPC: case MTTPC_B: case TABLETPC2FG: input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); - /*fall through */ + fallthrough; case TABLETPC: case TABLETPCE: @@ -3843,7 +3843,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, case INTUOSHT2: input_dev->evbit[0] |= BIT_MASK(EV_SW); __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - /* fall through */ + fallthrough; case BAMBOO_PT: case BAMBOO_TOUCH: @@ -4099,7 +4099,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, __set_bit(KEY_BUTTONCONFIG, input_dev->keybit); __set_bit(KEY_INFO, input_dev->keybit); - /* fall through */ + fallthrough; case WACOM_21UX2: case WACOM_BEE: @@ -4115,7 +4115,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS3: case INTUOS3L: input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); - /* fall through */ + fallthrough; case INTUOS3S: input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); @@ -4139,7 +4139,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, * ID_INPUT_TABLET to be set. */ __set_bit(BTN_STYLUS, input_dev->keybit); - /* fall through */ + fallthrough; case INTUOS4: case INTUOS4L: |