diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-07 11:13:42 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-07 11:13:42 -0700 |
commit | 79d11de9637a37035b4a72ccb528b3dfebc1bf67 (patch) | |
tree | 60e625591aa681bdb76a641b7084f15c990ba009 | |
parent | 5d435a3f7b6cb1db566d0f56f5f8dc33be0dde69 (diff) | |
parent | cb7c02e91c31f55d08760f04a09bf9334d809426 (diff) |
Merge tag 'for-linus-2022100501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Benjamin Tissoires:
- handle of all Logitech Bluetooth HID++ devices in the Logitech HID++
drivers (Bastien Nocera)
- fix broken atomic checks in hid-multitouch by adding memory barriers
(Andri Yngvason)
- better handling of devices with AMD SFH1.1 (Basavaraj Natikar)
- better support of Nintendo clone controllers (Icenowy Zheng and
Johnothan King)
- Support for various RC controllers (Marcus Folkesson)
- Add UGEEv2 support in hid-uclogic (XP-PEN Deco Pro S and Parblo A610
PRO) (José Expósito)
- some conversions to use dev_groups (Greg Kroah-Hartman)
- HID-BPF preparatory patches, mostly to convert blank defines as enums
(Benjamin Tissoires)
* tag 'for-linus-2022100501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (38 commits)
HID: wacom: add three styli to wacom_intuos_get_tool_type
HID: amd_sfh: Handle condition of "no sensors" for SFH1.1
HID: amd_sfh: Change dev_err to dev_dbg for additional debug info
HID: nintendo: check analog user calibration for plausibility
HID: nintendo: deregister home LED when it fails
HID: roccat: Fix use-after-free in roccat_read()
hid: topre: Add driver fixing report descriptor
HID: multitouch: Add memory barriers
HID: convert defines of HID class requests into a proper enum
HID: export hid_report_type to uapi
HID: core: store the unique system identifier in hid_device
HID: Add driver for PhoenixRC Flight Controller
HID: Add driver for VRC-2 Car Controller
HID: sony: Fix double word in comments
hid: hid-logitech-hidpp: avoid unnecessary assignments in hidpp_connect_event
HID: logitech-hidpp: Detect hi-res scrolling support
HID: logitech-hidpp: Remove hard-coded "Sw. Id." for HID++ 2.0 commands
HID: logitech-hidpp: Fix "Sw. Id." for HID++ 2.0 commands
HID: logitech-hidpp: Remove special-casing of Bluetooth devices
HID: logitech-hidpp: Enable HID++ for all the Logitech Bluetooth devices
...
38 files changed, 1034 insertions, 325 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1bf9e71bc8bb..43ba66d26a30 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9082,6 +9082,12 @@ L: linux-input@vger.kernel.org S: Supported F: drivers/hid/hid-playstation.c +HID PHOENIX RC FLIGHT CONTROLLER +M: Marcus Folkesson <marcus.folkesson@gmail.com> +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-pxrc.c + HID SENSOR HUB DRIVERS M: Jiri Kosina <jikos@kernel.org> M: Jonathan Cameron <jic23@kernel.org> @@ -9094,6 +9100,12 @@ F: drivers/hid/hid-sensor-* F: drivers/iio/*/hid-* F: include/linux/hid-sensor-* +HID VRC-2 CAR CONTROLLER DRIVER +M: Marcus Folkesson <marcus.folkesson@gmail.com> +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-vrc2.c + HID WACOM DRIVER M: Ping Cheng <ping.cheng@wacom.com> M: Jason Gerecke <jason.gerecke@wacom.com> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 6ce92830b5d1..185a077d59cd 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -28,7 +28,6 @@ if HID config HID_BATTERY_STRENGTH bool "Battery level reporting for HID devices" - depends on HID select POWER_SUPPLY default n help @@ -38,7 +37,6 @@ config HID_BATTERY_STRENGTH config HIDRAW bool "/dev/hidraw raw HID device support" - depends on HID help Say Y here if you want to support HID devices (from the USB specification standpoint) that aren't strictly user interface @@ -57,7 +55,6 @@ config HIDRAW config UHID tristate "User-space I/O driver support for HID subsystem" - depends on HID default n help Say Y here if you want to provide HID I/O Drivers from user-space. @@ -78,7 +75,6 @@ config UHID config HID_GENERIC tristate "Generic HID driver" - depends on HID default HID help Support for generic devices on the HID bus. This includes most @@ -90,11 +86,9 @@ config HID_GENERIC If unsure, say Y. menu "Special HID drivers" - depends on HID config HID_A4TECH tristate "A4TECH mice" - depends on HID default !EXPERT help Support for some A4TECH mice with two scroll wheels. @@ -113,7 +107,6 @@ config HID_ACCUTOUCH config HID_ACRUX tristate "ACRUX game controller support" - depends on HID help Say Y here if you want to enable support for ACRUX game controllers. @@ -127,7 +120,6 @@ config HID_ACRUX_FF config HID_APPLE tristate "Apple {i,Power,Mac}Books" - depends on HID depends on LEDS_CLASS depends on NEW_LEDS default !EXPERT @@ -167,13 +159,11 @@ config HID_ASUS config HID_AUREAL tristate "Aureal" - depends on HID 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 Support for Belkin Flip KVM and Wireless keyboard. @@ -202,7 +192,6 @@ config HID_BIGBEN_FF config HID_CHERRY tristate "Cherry Cymotion keyboard" - depends on HID default !EXPERT help Support for Cherry Cymotion keyboard. @@ -227,7 +216,6 @@ config HID_CORSAIR config HID_COUGAR tristate "Cougar devices" - depends on HID help Support for Cougar devices that are not fully compliant with the HID standard. @@ -237,7 +225,6 @@ config HID_COUGAR config HID_MACALLY tristate "Macally devices" - depends on HID help Support for Macally devices that are not fully compliant with the HID standard. @@ -262,7 +249,6 @@ config HID_PRODIKEYS config HID_CMEDIA tristate "CMedia audio chips" - depends on HID help Support for CMedia CM6533 HID audio jack controls and HS100B mute buttons. @@ -288,14 +274,12 @@ config HID_CREATIVE_SB0540 config HID_CYPRESS tristate "Cypress mouse and barcode readers" - depends on HID default !EXPERT help Support for cypress mouse and barcode readers. config HID_DRAGONRISE tristate "DragonRise Inc. game controller" - depends on HID help Say Y here if you have DragonRise Inc. game controllers. These might be branded as: @@ -314,7 +298,6 @@ config DRAGONRISE_FF config HID_EMS_FF tristate "EMS Production Inc. force feedback support" - depends on HID select INPUT_FF_MEMLESS help Say Y here if you want to enable force feedback support for devices by @@ -332,7 +315,6 @@ config HID_ELAN config HID_ELECOM tristate "ELECOM HID devices" - depends on HID help Support for ELECOM devices: - BM084 Bluetooth Mouse @@ -349,7 +331,6 @@ config HID_ELO config HID_EZKEY tristate "Ezkey BTC 8193 keyboard" - depends on HID default !EXPERT help Support for Ezkey BTC 8193 keyboard. @@ -367,19 +348,16 @@ config HID_FT260 config HID_GEMBIRD tristate "Gembird Joypad" - depends on HID help Support for Gembird JPD-DualForce 2. config HID_GFRM tristate "Google Fiber TV Box remote control support" - depends on HID help Support for Google Fiber TV Box remote controls config HID_GLORIOUS tristate "Glorious PC Gaming Race mice" - depends on HID help Support for Glorious PC Gaming Race mice such as the Glorious Model O, O- and D. @@ -424,7 +402,6 @@ config HID_VIVALDI tristate "Vivaldi Keyboard" select HID_VIVALDI_COMMON select INPUT_VIVALDIFMAP - depends on HID help Say Y here if you want to enable support for Vivaldi keyboards. @@ -447,7 +424,6 @@ config HID_GT683R config HID_KEYTOUCH tristate "Keytouch HID devices" - depends on HID help Support for Keytouch HID devices not fully compliant with the specification. Currently supported: @@ -455,7 +431,6 @@ config HID_KEYTOUCH config HID_KYE tristate "KYE/Genius devices" - depends on HID help Support for KYE/Genius devices not fully compliant with HID standard: - Ergo Mouse @@ -471,32 +446,37 @@ config HID_UCLOGIC config HID_WALTOP tristate "Waltop" - depends on HID help Support for Waltop tablets. config HID_VIEWSONIC tristate "ViewSonic/Signotec" - depends on HID help Support for ViewSonic/Signotec PD1011 signature pad. +config HID_VRC2 + tristate "VRC-2 Car Controller" + depends on HID + help + Support for VRC-2 which is a 2-axis controller often used in + car simulators. + + To compile this driver as a module, choose M here: the + module will be called hid-vrc2. + config HID_XIAOMI tristate "Xiaomi" - depends on HID help Adds support for side buttons of Xiaomi Mi Dual Mode Wireless Mouse Silent Edition. config HID_GYRATION tristate "Gyration remote control" - depends on HID help Support for Gyration remote control. config HID_ICADE tristate "ION iCade arcade controller" - depends on HID help Support for the ION iCade arcade controller to work as a joystick. @@ -505,14 +485,12 @@ config HID_ICADE config HID_ITE tristate "ITE devices" - depends on HID default !EXPERT help Support for ITE devices not fully compliant with HID standard. config HID_JABRA tristate "Jabra USB HID Driver" - depends on HID help Support for Jabra USB HID devices. @@ -523,26 +501,22 @@ config HID_JABRA config HID_TWINHAN tristate "Twinhan IR remote control" - depends on HID help Support for Twinhan IR remote control. config HID_KENSINGTON tristate "Kensington Slimblade Trackball" - depends on HID default !EXPERT help Support for Kensington Slimblade Trackball. config HID_LCPOWER tristate "LC-Power" - depends on HID 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 Support for simple RGB LED devices. Currently supported are: @@ -557,7 +531,6 @@ config HID_LED config HID_LENOVO tristate "Lenovo / Thinkpad devices" - depends on HID select NEW_LEDS select LEDS_CLASS help @@ -675,7 +648,6 @@ config LOGIWHEELS_FF config HID_MAGICMOUSE tristate "Apple Magic Mouse/Trackpad multi-touch support" - depends on HID help Support for the Apple Magic Mouse/Trackpad multi-touch. @@ -684,14 +656,12 @@ config HID_MAGICMOUSE config HID_MALTRON tristate "Maltron L90 keyboard" - depends on HID help Adds support for the volume up, volume down, mute, and play/pause buttons of the Maltron L90 keyboard. config HID_MAYFLASH tristate "Mayflash game controller adapter force feedback" - depends on HID select INPUT_FF_MEMLESS help Say Y here if you have HJZ Mayflash PS3 game controller adapters @@ -707,14 +677,12 @@ config HID_MEGAWORLD_FF config HID_REDRAGON tristate "Redragon keyboards" - depends on HID default !EXPERT help Support for Redragon keyboards that need fix-ups to work properly. config HID_MICROSOFT tristate "Microsoft non-fully HID-compliant devices" - depends on HID default !EXPERT select INPUT_FF_MEMLESS help @@ -722,14 +690,12 @@ config HID_MICROSOFT config HID_MONTEREY tristate "Monterey Genius KB29E keyboard" - depends on HID default !EXPERT help Support for Monterey Genius KB29E. config HID_MULTITOUCH tristate "HID Multitouch panels" - depends on HID help Generic support for HID multitouch panels. @@ -775,7 +741,6 @@ config HID_MULTITOUCH config HID_NINTENDO tristate "Nintendo Joy-Con and Pro Controller support" - depends on HID depends on NEW_LEDS depends on LEDS_CLASS select POWER_SUPPLY @@ -811,7 +776,6 @@ config HID_NTRIG config HID_ORTEK tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad" - depends on HID help There are certain devices which have LogicalMaximum wrong in the keyboard usage page of their report descriptor. The most prevailing ones so far @@ -824,7 +788,6 @@ config HID_ORTEK config HID_PANTHERLORD tristate "Pantherlord/GreenAsia game controller" - depends on HID help Say Y here if you have a PantherLord/GreenAsia based game controller or adapter. @@ -850,13 +813,11 @@ config HID_PENMOUNT config HID_PETALYNX tristate "Petalynx Maxter remote control" - depends on HID help Support for Petalynx Maxter remote control. config HID_PICOLCD tristate "PicoLCD (graphic version)" - depends on HID help This provides support for Minibox PicoLCD devices, currently only the graphical ones are supported. @@ -922,7 +883,6 @@ config HID_PICOLCD_CIR config HID_PLANTRONICS tristate "Plantronics USB HID Driver" - depends on HID help Provides HID support for Plantronics USB audio devices. Correctly maps vendor unique volume up/down HID usages to @@ -933,7 +893,6 @@ config HID_PLANTRONICS config HID_PLAYSTATION tristate "PlayStation HID Driver" - depends on HID depends on LEDS_CLASS_MULTICOLOR select CRC32 select POWER_SUPPLY @@ -950,16 +909,23 @@ config PLAYSTATION_FF Say Y here if you would like to enable force feedback support for PlayStation game controllers. +config HID_PXRC + tristate "PhoenixRC HID Flight Controller" + depends on HID + help + Support for PhoenixRC HID Flight Controller, a 8-axis flight controller. + + To compile this driver as a module, choose M here: the + module will be called hid-pxrc. + config HID_RAZER tristate "Razer non-fully HID-compliant devices" - depends on HID help Support for Razer devices that are not fully compliant with the HID standard. config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" - depends on HID help Support for Primax devices that are not fully compliant with the HID standard. @@ -981,7 +947,6 @@ config HID_ROCCAT config HID_SAITEK tristate "Saitek (Mad Catz) non-fully HID-compliant devices" - depends on HID help Support for Saitek devices that are not fully compliant with the HID standard. @@ -999,7 +964,6 @@ config HID_SAMSUNG config HID_SEMITEK tristate "Semitek USB keyboards" - depends on HID help Support for Semitek USB keyboards that are not fully compliant with the HID standard. @@ -1050,13 +1014,11 @@ config SONY_FF config HID_SPEEDLINK tristate "Speedlink VAD Cezanne mouse support" - depends on HID help Support for Speedlink Vicious and Divine Cezanne mouse. config HID_STEAM tristate "Steam Controller support" - depends on HID select POWER_SUPPLY help Say Y here if you have a Steam Controller if you want to use it @@ -1065,19 +1027,16 @@ config HID_STEAM config HID_STEELSERIES tristate "Steelseries SRW-S1 steering wheel support" - depends on HID help Support for Steelseries SRW-S1 steering wheel config HID_SUNPLUS tristate "Sunplus wireless desktop" - depends on HID help Support for Sunplus wireless desktop. config HID_RMI tristate "Synaptics RMI4 device support" - depends on HID select RMI4_CORE select RMI4_F03 select RMI4_F11 @@ -1090,7 +1049,6 @@ config HID_RMI config HID_GREENASIA tristate "GreenAsia (Product ID 0x12) game controller support" - depends on HID help Say Y here if you have a GreenAsia (Product ID 0x12) based game controller or adapter. @@ -1112,7 +1070,6 @@ config HID_HYPERV_MOUSE config HID_SMARTJOYPLUS tristate "SmartJoy PLUS PS2/USB adapter support" - depends on HID 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. @@ -1130,20 +1087,23 @@ config SMARTJOYPLUS_FF config HID_TIVO tristate "TiVo Slide Bluetooth remote control support" - depends on HID 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 Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic CLLRCMCE remote control. +config HID_TOPRE + tristate "Topre REALFORCE keyboards" + depends on HID + help + Say Y for N-key rollover support on Topre REALFORCE R2 108 key keyboards. + config HID_THINGM tristate "ThingM blink(1) USB RGB LED" - depends on HID depends on LEDS_CLASS select HID_LED help @@ -1170,7 +1130,6 @@ config THRUSTMASTER_FF config HID_UDRAW_PS3 tristate "THQ PS3 uDraw tablet" - depends on HID help Say Y here if you want to use the THQ uDraw gaming tablet for the PS3. @@ -1207,7 +1166,6 @@ config HID_WACOM config HID_WIIMOTE tristate "Nintendo Wii / Wii U peripherals" - depends on HID depends on LEDS_CLASS select POWER_SUPPLY select INPUT_FF_MEMLESS @@ -1232,7 +1190,6 @@ config HID_WIIMOTE config HID_XINMO tristate "Xin-Mo non-fully compliant devices" - depends on HID 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 @@ -1240,7 +1197,6 @@ config HID_XINMO config HID_ZEROPLUS tristate "Zeroplus based game controller support" - depends on HID help Say Y here if you have a Zeroplus based game controller. @@ -1254,13 +1210,12 @@ config ZEROPLUS_FF config HID_ZYDACRON tristate "Zydacron remote control support" - depends on HID help Support for Zydacron remote control. config HID_SENSOR_HUB tristate "HID Sensors framework support" - depends on HID && HAS_IOMEM + depends on HAS_IOMEM select MFD_CORE default n help @@ -1289,7 +1244,6 @@ config HID_SENSOR_CUSTOM_SENSOR config HID_ALPS tristate "Alps HID device support" - depends on HID help Support for Alps I2C HID touchpads and StickPointer. Say Y here if you have a Alps touchpads over i2c-hid or usbhid @@ -1307,7 +1261,7 @@ config HID_MCP2221 will be called hid-mcp2221.ko. config HID_KUNIT_TEST - bool "KUnit tests for HID" if !KUNIT_ALL_TESTS + tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS depends on KUNIT=y depends on HID_UCLOGIC default KUNIT_ALL_TESTS diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b0bef8098139..e8014c1a2f8b 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -101,6 +101,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o +obj-$(CONFIG_HID_PXRC) += hid-pxrc.o obj-$(CONFIG_HID_RAZER) += hid-razer.o obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o obj-$(CONFIG_HID_RETRODE) += hid-retrode.o @@ -123,6 +124,7 @@ obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o hid-thrustmaster.o obj-$(CONFIG_HID_TIVO) += hid-tivo.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o +obj-$(CONFIG_HID_TOPRE) += hid-topre.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o obj-$(CONFIG_HID_U2FZERO) += hid-u2fzero.o hid-uclogic-objs := hid-uclogic-core.o \ @@ -136,6 +138,7 @@ obj-$(CONFIG_HID_XINMO) += hid-xinmo.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_VIEWSONIC) += hid-viewsonic.o +obj-$(CONFIG_HID_VRC2) += hid-vrc2.o wacom-objs := wacom_wac.o wacom_sys.o obj-$(CONFIG_HID_WACOM) += wacom.o @@ -144,8 +147,10 @@ obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o -obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \ +hid-uclogic-test-objs := hid-uclogic-rdesc.o \ + hid-uclogic-params.o \ hid-uclogic-rdesc-test.o +obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-test.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c index 70436f9fad2f..4da2f9f62aba 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c @@ -110,6 +110,8 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata) amd_sfh1_1_set_desc_ops(mp2_ops); cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]); + if (cl_data->num_hid_devices == 0) + return -ENODEV; INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); @@ -286,13 +288,13 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2) phy_base <<= 21; if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) { - dev_err(dev, "can't reserve mmio registers\n"); + dev_dbg(dev, "can't reserve mmio registers\n"); return -ENOMEM; } mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024); if (!mp2->vsbase) { - dev_err(dev, "failed to remap vsbase\n"); + dev_dbg(dev, "failed to remap vsbase\n"); return -ENOMEM; } @@ -301,7 +303,7 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2) memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) { - dev_err(dev, "failed to get sensors\n"); + dev_dbg(dev, "failed to get sensors\n"); return -EOPNOTSUPP; } dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b7f5566e338d..9c1d31f63f85 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle */ struct hid_report *hid_register_report(struct hid_device *device, - unsigned int type, unsigned int id, + enum hid_report_type type, unsigned int id, unsigned int application) { struct hid_report_enum *report_enum = device->report_enum + type; @@ -967,7 +967,7 @@ static const char * const hid_report_names[] = { * parsing. */ struct hid_report *hid_validate_values(struct hid_device *hid, - unsigned int type, unsigned int id, + enum hid_report_type type, unsigned int id, unsigned int field_index, unsigned int report_counts) { @@ -1921,7 +1921,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, * DO NOT USE in hid drivers directly, but through hid_hw_request instead. */ int __hid_request(struct hid_device *hid, struct hid_report *report, - int reqtype) + enum hid_class_request reqtype) { char *buf; int ret; @@ -1954,8 +1954,8 @@ out: } EXPORT_SYMBOL_GPL(__hid_request); -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, - int interrupt) +int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, + int interrupt) { struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; @@ -2019,7 +2019,8 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); * * This is data entry for lower layers. */ -int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) +int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, + int interrupt) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; @@ -2088,6 +2089,7 @@ const struct hid_device_id *hid_match_id(const struct hid_device *hdev, return NULL; } +EXPORT_SYMBOL_GPL(hid_match_id); static const struct hid_device_id hid_hiddev_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) }, @@ -2352,7 +2354,7 @@ EXPORT_SYMBOL_GPL(hid_hw_close); * @reqtype: hid request type */ void hid_hw_request(struct hid_device *hdev, - struct hid_report *report, int reqtype) + struct hid_report *report, enum hid_class_request reqtype) { if (hdev->ll_driver->request) return hdev->ll_driver->request(hdev, report, reqtype); @@ -2377,7 +2379,7 @@ EXPORT_SYMBOL_GPL(hid_hw_request); */ int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, - size_t len, unsigned char rtype, int reqtype) + size_t len, enum hid_report_type rtype, enum hid_class_request reqtype) { if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) return -EINVAL; @@ -2739,10 +2741,12 @@ int hid_add_device(struct hid_device *hdev) hid_warn(hdev, "bad device descriptor (%d)\n", ret); } + hdev->id = atomic_inc_return(&id); + /* XXX hack, any other cleaner solution after the driver core * is converted to allow more than 20 bytes as the device name? */ dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, - hdev->vendor, hdev->product, atomic_inc_return(&id)); + hdev->vendor, hdev->product, hdev->id); hid_debug_register(hdev, dev_name(&hdev->dev)); ret = device_add(&hdev->dev); diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index ff40f1e55c21..7ae5f27df54d 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -608,9 +608,11 @@ static struct hid_driver hammer_driver = { .probe = hammer_probe, .remove = hammer_remove, .feature_mapping = vivaldi_feature_mapping, - .input_configured = vivaldi_input_configured, .input_mapping = hammer_input_mapping, .event = hammer_event, + .driver = { + .dev_groups = vivaldi_attribute_groups, + }, }; static int __init hammer_init(void) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f80d6193fca6..da86565f04d4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1231,6 +1231,9 @@ #define USB_DEVICE_ID_TIVO_SLIDE 0x1201 #define USB_DEVICE_ID_TIVO_SLIDE_PRO 0x1203 +#define USB_VENDOR_ID_TOPRE 0x0853 +#define USB_DEVICE_ID_TOPRE_REALFORCE_R2_108 0x0148 + #define USB_VENDOR_ID_TOPSEED 0x0766 #define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204 @@ -1279,10 +1282,12 @@ #define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d #define USB_VENDOR_ID_UGEE 0x28bd +#define USB_DEVICE_ID_UGEE_PARBLO_A610_PRO 0x1903 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 @@ -1386,6 +1391,7 @@ #define USB_VENDOR_ID_MULTIPLE_1781 0x1781 #define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a9d +#define USB_DEVICE_ID_PHOENIXRC 0x0898 #define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b #define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002 diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 68f9e9d207f4..71a9c258a20b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -41,6 +41,9 @@ module_param(disable_tap_to_click, bool, 0644); MODULE_PARM_DESC(disable_tap_to_click, "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently)."); +/* Define a non-zero software ID to identify our own requests */ +#define LINUX_KERNEL_SW_ID 0x01 + #define REPORT_ID_HIDPP_SHORT 0x10 #define REPORT_ID_HIDPP_LONG 0x11 #define REPORT_ID_HIDPP_VERY_LONG 0x12 @@ -71,21 +74,18 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_UNIFYING BIT(25) -#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) -#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) -#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) -#define HIDPP_QUIRK_HIDPP_WHEELS BIT(29) -#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(30) -#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(31) +#define HIDPP_QUIRK_HIDPP_WHEELS BIT(26) +#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27) +#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28) /* These are just aliases for now */ #define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS #define HIDPP_QUIRK_KBD_ZOOM_WHEEL HIDPP_QUIRK_HIDPP_WHEELS /* Convenience constant to check for any high-res support. */ -#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ - HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ - HIDPP_QUIRK_HI_RES_SCROLL_X2121) +#define HIDPP_CAPABILITY_HI_RES_SCROLL (HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL | \ + HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \ + HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT @@ -96,6 +96,9 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4) #define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5) #define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6) +#define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL BIT(7) +#define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL BIT(8) +#define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL BIT(9) #define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) @@ -343,7 +346,7 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, else message->report_id = REPORT_ID_HIDPP_LONG; message->fap.feature_index = feat_index; - message->fap.funcindex_clientid = funcindex_clientid; + message->fap.funcindex_clientid = funcindex_clientid | LINUX_KERNEL_SW_ID; memcpy(&message->fap.params, params, param_count); ret = hidpp_send_message_sync(hidpp, message, response); @@ -856,8 +859,8 @@ static int hidpp_unifying_init(struct hidpp_device *hidpp) #define HIDPP_PAGE_ROOT 0x0000 #define HIDPP_PAGE_ROOT_IDX 0x00 -#define CMD_ROOT_GET_FEATURE 0x01 -#define CMD_ROOT_GET_PROTOCOL_VERSION 0x11 +#define CMD_ROOT_GET_FEATURE 0x00 +#define CMD_ROOT_GET_PROTOCOL_VERSION 0x10 static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature, u8 *feature_index, u8 *feature_type) @@ -934,9 +937,9 @@ print_version: #define HIDPP_PAGE_GET_DEVICE_NAME_TYPE 0x0005 -#define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x01 -#define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x11 -#define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x21 +#define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x00 +#define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x10 +#define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x20 static int hidpp_devicenametype_get_count(struct hidpp_device *hidpp, u8 feature_index, u8 *nameLength) @@ -1966,8 +1969,8 @@ static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp, #define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100 -#define CMD_TOUCHPAD_GET_RAW_INFO 0x01 -#define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x21 +#define CMD_TOUCHPAD_GET_RAW_INFO 0x00 +#define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x20 #define EVENT_TOUCHPAD_RAW_XY 0x00 @@ -3415,14 +3418,14 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp) int ret; u8 multiplier = 1; - if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { + if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) { ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); if (ret == 0) ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier); - } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { + } else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) { ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, &multiplier); - } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { + } else /* if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL) */ { ret = hidpp10_enable_scrolling_acceleration(hidpp); multiplier = 8; } @@ -3437,6 +3440,49 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp) return 0; } +static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp) +{ + int ret; + unsigned long capabilities; + + capabilities = hidpp->capabilities; + + if (hidpp->protocol_major >= 2) { + u8 feature_index; + u8 feature_type; + + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, + &feature_index, &feature_type); + if (!ret) { + hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL; + hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scroll wheel\n"); + return 0; + } + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HI_RESOLUTION_SCROLLING, + &feature_index, &feature_type); + if (!ret) { + hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL; + hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n"); + } + } else { + struct hidpp_report response; + + ret = hidpp_send_rap_command_sync(hidpp, + REPORT_ID_HIDPP_SHORT, + HIDPP_GET_REGISTER, + HIDPP_ENABLE_FAST_SCROLL, + NULL, 0, &response); + if (!ret) { + hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL; + hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n"); + } + } + + if (hidpp->capabilities == capabilities) + hid_dbg(hidpp->hid_dev, "Did not detect HID++ hi-res scrolling hardware support\n"); + return 0; +} + /* -------------------------------------------------------------------------- */ /* Generic HID++ devices */ /* -------------------------------------------------------------------------- */ @@ -3691,8 +3737,9 @@ static int hidpp_event(struct hid_device *hdev, struct hid_field *field, * cases we must return early (falling back to default behaviour) to * avoid a crash in hidpp_scroll_counter_handle_scroll. */ - if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 - || hidpp->input == NULL || counter->wheel_multiplier == 0) + if (!(hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL) + || value == 0 || hidpp->input == NULL + || counter->wheel_multiplier == 0) return 0; hidpp_scroll_counter_handle_scroll(hidpp->input, counter, value); @@ -3924,6 +3971,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) } hidpp_initialize_battery(hidpp); + hidpp_initialize_hires_scroll(hidpp); /* forward current battery state */ if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) { @@ -3943,7 +3991,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) if (hidpp->battery.ps) power_supply_changed(hidpp->battery.ps); - if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) + if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL) hi_res_scroll_enable(hidpp); if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) @@ -3959,8 +4007,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) hidpp_populate_input(hidpp, input); ret = input_register_device(input); - if (ret) + if (ret) { input_free_device(input); + return; + } hidpp->delayed_input = input; } @@ -4219,6 +4269,21 @@ static void hidpp_remove(struct hid_device *hdev) mutex_destroy(&hidpp->send_mutex); } +static const struct hid_device_id unhandled_hidpp_devices[] = { + /* Logitech Harmony Adapter for PS3, handled in hid-sony */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, + /* Handled in hid-generic */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD) }, + {} +}; + +static bool hidpp_match(struct hid_device *hdev, + bool ignore_special_driver) +{ + /* Refuse to handle devices handled by other HID drivers */ + return !hid_match_id(hdev, unhandled_hidpp_devices); +} + #define LDJ_DEVICE(product) \ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ USB_VENDOR_ID_LOGITECH, (product)) @@ -4239,42 +4304,9 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651), .driver_data = HIDPP_QUIRK_CLASS_WTP }, - { /* Mouse Logitech Anywhere MX */ - LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, - { /* Mouse Logitech Cube */ - LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, - { /* Mouse Logitech M335 */ - LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech M515 */ - LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, { /* Mouse logitech M560 */ LDJ_DEVICE(0x402d), - .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 - | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, - { /* Mouse Logitech M705 (firmware RQM17) */ - LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, - { /* Mouse Logitech M705 (firmware RQM67) */ - LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech M720 */ - LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech MX Anywhere 2 */ - LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech MX Anywhere 2S */ - LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech MX Master */ - LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech MX Master 2S */ - LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech MX Master 3 */ - LDJ_DEVICE(0x4082), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* Mouse Logitech Performance MX */ - LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, { /* Keyboard logitech K400 */ LDJ_DEVICE(0x4024), .driver_data = HIDPP_QUIRK_CLASS_K400 }, @@ -4335,18 +4367,9 @@ static const struct hid_device_id hidpp_devices[] = { { /* MX5500 keyboard over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, - { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */ - HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) }, - { /* MX Master mouse over Bluetooth */ - HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012), - .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* MX Ergo trackball over Bluetooth */ - HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e), - .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, - { /* MX Master 3 mouse over Bluetooth */ - HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023), - .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + + { /* And try to enable HID++ for all the Logitech Bluetooth devices */ + HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_ANY, USB_VENDOR_ID_LOGITECH, HID_ANY_ID) }, {} }; @@ -4360,6 +4383,7 @@ static const struct hid_usage_id hidpp_usages[] = { static struct hid_driver hidpp_driver = { .name = "logitech-hidpp-device", .id_table = hidpp_devices, + .match = hidpp_match, .report_fixup = hidpp_report_fixup, .probe = hidpp_probe, .remove = hidpp_remove, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 2e72922e36f5..91a4d3fc30e0 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1186,7 +1186,7 @@ static void mt_touch_report(struct hid_device *hid, int contact_count = -1; /* sticky fingers release in progress, abort */ - if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) + if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) return; scantime = *app->scantime; @@ -1267,7 +1267,7 @@ static void mt_touch_report(struct hid_device *hid, del_timer(&td->release_timer); } - clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } static int mt_touch_input_configured(struct hid_device *hdev, @@ -1699,11 +1699,11 @@ static void mt_expired_timeout(struct timer_list *t) * An input report came in just before we release the sticky fingers, * it will take care of the sticky fingers. */ - if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) + if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) return; if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) mt_release_contacts(hdev); - clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); } static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 6028af3c3aae..5bfc0c450460 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -760,12 +760,31 @@ static int joycon_read_stick_calibration(struct joycon_ctlr *ctlr, u16 cal_addr, cal_y->max = cal_y->center + y_max_above; cal_y->min = cal_y->center - y_min_below; - return 0; + /* check if calibration values are plausible */ + if (cal_x->min >= cal_x->center || cal_x->center >= cal_x->max || + cal_y->min >= cal_y->center || cal_y->center >= cal_y->max) + ret = -EINVAL; + + return ret; } static const u16 DFLT_STICK_CAL_CEN = 2000; static const u16 DFLT_STICK_CAL_MAX = 3500; static const u16 DFLT_STICK_CAL_MIN = 500; +static void joycon_use_default_calibration(struct hid_device *hdev, + struct joycon_stick_cal *cal_x, + struct joycon_stick_cal *cal_y, + const char *stick, int ret) +{ + hid_warn(hdev, + "Failed to read %s stick cal, using defaults; e=%d\n", + stick, ret); + + cal_x->center = cal_y->center = DFLT_STICK_CAL_CEN; + cal_x->max = cal_y->max = DFLT_STICK_CAL_MAX; + cal_x->min = cal_y->min = DFLT_STICK_CAL_MIN; +} + static int joycon_request_calibration(struct joycon_ctlr *ctlr) { u16 left_stick_addr = JC_CAL_FCT_DATA_LEFT_ADDR; @@ -793,38 +812,24 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr) &ctlr->left_stick_cal_x, &ctlr->left_stick_cal_y, true); - if (ret) { - hid_warn(ctlr->hdev, - "Failed to read left stick cal, using dflts; e=%d\n", - ret); - ctlr->left_stick_cal_x.center = DFLT_STICK_CAL_CEN; - ctlr->left_stick_cal_x.max = DFLT_STICK_CAL_MAX; - ctlr->left_stick_cal_x.min = DFLT_STICK_CAL_MIN; - - ctlr->left_stick_cal_y.center = DFLT_STICK_CAL_CEN; - ctlr->left_stick_cal_y.max = DFLT_STICK_CAL_MAX; - ctlr->left_stick_cal_y.min = DFLT_STICK_CAL_MIN; - } + if (ret) + joycon_use_default_calibration(ctlr->hdev, + &ctlr->left_stick_cal_x, + &ctlr->left_stick_cal_y, + "left", ret); /* read the right stick calibration data */ ret = joycon_read_stick_calibration(ctlr, right_stick_addr, &ctlr->right_stick_cal_x, &ctlr->right_stick_cal_y, false); - if (ret) { - hid_warn(ctlr->hdev, - "Failed to read right stick cal, using dflts; e=%d\n", - ret); - - ctlr->right_stick_cal_x.center = DFLT_STICK_CAL_CEN; - ctlr->right_stick_cal_x.max = DFLT_STICK_CAL_MAX; - ctlr->right_stick_cal_x.min = DFLT_STICK_CAL_MIN; - ctlr->right_stick_cal_y.center = DFLT_STICK_CAL_CEN; - ctlr->right_stick_cal_y.max = DFLT_STICK_CAL_MAX; - ctlr->right_stick_cal_y.min = DFLT_STICK_CAL_MIN; - } + if (ret) + joycon_use_default_calibration(ctlr->hdev, + &ctlr->right_stick_cal_x, + &ctlr->right_stick_cal_y, + "right", ret); hid_dbg(ctlr->hdev, "calibration:\n" "l_x_c=%d l_x_max=%d l_x_min=%d\n" @@ -1904,9 +1909,8 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr) /* Set the home LED to 0 as default state */ ret = joycon_home_led_brightness_set(led, 0); if (ret) { - hid_err(hdev, "Failed to set home LED dflt; ret=%d\n", - ret); - return ret; + hid_warn(hdev, "Failed to set home LED default, unregistering home LED"); + devm_led_classdev_unregister(&hdev->dev, led); } } diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index b1b5721b5d8f..40050eb85c0a 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -692,15 +692,12 @@ static ssize_t hardware_version_show(struct device *dev, static DEVICE_ATTR_RO(hardware_version); -static struct attribute *ps_device_attributes[] = { +static struct attribute *ps_device_attrs[] = { &dev_attr_firmware_version.attr, &dev_attr_hardware_version.attr, NULL }; - -static const struct attribute_group ps_device_attribute_group = { - .attrs = ps_device_attributes, -}; +ATTRIBUTE_GROUPS(ps_device); static int dualsense_get_calibration_data(struct dualsense *ds) { @@ -1448,12 +1445,6 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) } } - ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group); - if (ret) { - hid_err(hdev, "Failed to register sysfs nodes.\n"); - goto err_close; - } - return ret; err_close: @@ -1487,6 +1478,9 @@ static struct hid_driver ps_driver = { .probe = ps_probe, .remove = ps_remove, .raw_event = ps_raw_event, + .driver = { + .dev_groups = ps_device_groups, + }, }; static int __init ps_init(void) diff --git a/drivers/hid/hid-pxrc.c b/drivers/hid/hid-pxrc.c new file mode 100644 index 000000000000..b0e517f9cde7 --- /dev/null +++ b/drivers/hid/hid-pxrc.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for PhoenixRC 8-axis flight controller + * + * Copyright (C) 2022 Marcus Folkesson <marcus.folkesson@gmail.com> + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +struct pxrc_priv { + u8 slider; + u8 dial; + bool alternate; +}; + +static __u8 pxrc_rdesc_fixed[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x09, 0x30, // Usage (X) + 0x09, 0x36, // Usage (Slider) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x37, // Usage (Dial) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +static __u8 *pxrc_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + hid_info(hdev, "fixing up PXRC report descriptor\n"); + *rsize = sizeof(pxrc_rdesc_fixed); + return pxrc_rdesc_fixed; +} + +static int pxrc_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + struct pxrc_priv *priv = hid_get_drvdata(hdev); + + if (priv->alternate) + priv->slider = data[7]; + else + priv->dial = data[7]; + + data[1] = priv->slider; + data[7] = priv->dial; + + priv->alternate = !priv->alternate; + return 0; +} + +static int pxrc_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct pxrc_priv *priv; + + priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + hid_set_drvdata(hdev, priv); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + return 0; +} + +static const struct hid_device_id pxrc_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_PHOENIXRC) }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(hid, pxrc_devices); + +static struct hid_driver pxrc_driver = { + .name = "hid-pxrc", + .id_table = pxrc_devices, + .report_fixup = pxrc_report_fixup, + .probe = pxrc_probe, + .raw_event = pxrc_raw_event, +}; +module_hid_driver(pxrc_driver); + +MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>"); +MODULE_DESCRIPTION("HID driver for PXRC 8-axis flight controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 311eee599ce9..bb1f423f4ace 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -237,8 +237,7 @@ static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr, read_input_count = data->readReport[1]; memcpy(buf + bytes_read, &data->readReport[2], - read_input_count < bytes_needed ? - read_input_count : bytes_needed); + min(read_input_count, bytes_needed)); bytes_read += read_input_count; bytes_needed -= read_input_count; @@ -347,8 +346,7 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size) return 0; } - memcpy(hdata->readReport, data, size < hdata->input_report_size ? - size : hdata->input_report_size); + memcpy(hdata->readReport, data, min((u32)size, hdata->input_report_size)); set_bit(RMI_READ_DATA_PENDING, &hdata->flags); wake_up(&hdata->wait); diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index 26373b82fe81..6da80e442fdd 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -257,6 +257,8 @@ int roccat_report_event(int minor, u8 const *data) if (!new_value) return -ENOMEM; + mutex_lock(&device->cbuf_lock); + report = &device->cbuf[device->cbuf_end]; /* passing NULL is safe */ @@ -276,6 +278,8 @@ int roccat_report_event(int minor, u8 const *data) reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE; } + mutex_unlock(&device->cbuf_lock); + wake_up_interruptible(&device->wait); return 0; } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 60ec2b29d54d..03691cdcfb8e 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -368,7 +368,7 @@ static const unsigned int buzz_keymap[] = { }; /* The Navigation controller is a partial DS3 and uses the same HID report - * and hence the same keymap indices, however not not all axes/buttons + * and hence the same keymap indices, however not all axes/buttons * are physically present. We use the same axis and button mapping as * the DS3, which uses the Linux gamepad spec. */ diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index fc616db4231b..8ee43cb225fc 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -256,7 +256,7 @@ static int steam_get_serial(struct steam_device *steam) if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) return -EIO; reply[3 + STEAM_SERIAL_LEN] = 0; - strlcpy(steam->serial_no, reply + 3, sizeof(steam->serial_no)); + strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no)); return 0; } @@ -524,7 +524,7 @@ static int steam_register(struct steam_device *steam) */ mutex_lock(&steam->mutex); if (steam_get_serial(steam) < 0) - strlcpy(steam->serial_no, "XXXXXXXXXX", + strscpy(steam->serial_no, "XXXXXXXXXX", sizeof(steam->serial_no)); mutex_unlock(&steam->mutex); @@ -699,9 +699,9 @@ static struct hid_device *steam_create_client_hid(struct hid_device *hdev) client_hdev->version = hdev->version; client_hdev->type = hdev->type; client_hdev->country = hdev->country; - strlcpy(client_hdev->name, hdev->name, + strscpy(client_hdev->name, hdev->name, sizeof(client_hdev->name)); - strlcpy(client_hdev->phys, hdev->phys, + strscpy(client_hdev->phys, hdev->phys, sizeof(client_hdev->phys)); /* * Since we use the same device info than the real interface to diff --git a/drivers/hid/hid-topre.c b/drivers/hid/hid-topre.c new file mode 100644 index 000000000000..88a91cdad5f8 --- /dev/null +++ b/drivers/hid/hid-topre.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Topre REALFORCE Keyboards + * + * Copyright (c) 2022 Harry Stern <harry@harrystern.net> + * + * Based on the hid-macally driver + */ + +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +MODULE_AUTHOR("Harry Stern <harry@harrystern.net>"); +MODULE_DESCRIPTION("REALFORCE R2 Keyboard driver"); +MODULE_LICENSE("GPL"); + +/* + * Fix the REALFORCE R2's non-boot interface's report descriptor to match the + * events it's actually sending. It claims to send array events but is instead + * sending variable events. + */ +static __u8 *topre_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize >= 119 && rdesc[69] == 0x29 && rdesc[70] == 0xe7 && + rdesc[71] == 0x81 && rdesc[72] == 0x00) { + hid_info(hdev, + "fixing up Topre REALFORCE keyboard report descriptor\n"); + rdesc[72] = 0x02; + } + return rdesc; +} + +static const struct hid_device_id topre_id_table[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_TOPRE, + USB_DEVICE_ID_TOPRE_REALFORCE_R2_108) }, + { } +}; +MODULE_DEVICE_TABLE(hid, topre_id_table); + +static struct hid_driver topre_driver = { + .name = "topre", + .id_table = topre_id_table, + .report_fixup = topre_report_fixup, +}; + +module_hid_driver(topre_driver); diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 47a17375c7fc..0fbc408c2607 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -153,6 +153,7 @@ static int uclogic_input_configured(struct hid_device *hdev, suffix = "Pad"; break; case HID_DG_PEN: + case HID_DG_DIGITIZER: suffix = "Pen"; break; case HID_CP_CONSUMER_CONTROL: @@ -510,6 +511,8 @@ static const struct hid_device_id uclogic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GT5040) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_PARBLO_A610_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_G5) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) }, @@ -524,6 +527,8 @@ static const struct hid_device_id uclogic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, { } }; diff --git a/drivers/hid/hid-uclogic-params-test.c b/drivers/hid/hid-uclogic-params-test.c new file mode 100644 index 000000000000..57ef5d3e4b74 --- /dev/null +++ b/drivers/hid/hid-uclogic-params-test.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * HID driver for UC-Logic devices not fully compliant with HID standard + * + * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> + */ + +#include <kunit/test.h> +#include "./hid-uclogic-params.h" +#include "./hid-uclogic-rdesc.h" + +#define MAX_STR_DESC_SIZE 14 + +struct uclogic_parse_ugee_v2_desc_case { + const char *name; + int res; + const __u8 str_desc[MAX_STR_DESC_SIZE]; + size_t str_desc_size; + const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; + enum uclogic_params_frame_type frame_type; +}; + +static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = { + { + .name = "invalid_str_desc", + .res = -EINVAL, + .str_desc = {}, + .str_desc_size = 0, + .desc_params = {}, + .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, + }, + { + .name = "resolution_with_value_0", + .res = 0, + .str_desc = { + 0x0E, 0x03, + 0x70, 0xB2, + 0x10, 0x77, + 0x08, + 0x00, + 0xFF, 0x1F, + 0x00, 0x00, + }, + .str_desc_size = 12, + .desc_params = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0, + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0, + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, + }, + .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, + }, + /* XP-PEN Deco L str_desc: Frame with 8 buttons */ + { + .name = "frame_type_buttons", + .res = 0, + .str_desc = { + 0x0E, 0x03, + 0x70, 0xB2, + 0x10, 0x77, + 0x08, + 0x00, + 0xFF, 0x1F, + 0xD8, 0x13, + }, + .str_desc_size = 12, + .desc_params = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2320, + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710, + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1770, + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, + }, + .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS, + }, + /* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */ + { + .name = "frame_type_dial", + .res = 0, + .str_desc = { + 0x0E, 0x03, + 0x96, 0xC7, + 0xF9, 0x7C, + 0x09, + 0x01, + 0xFF, 0x1F, + 0xD8, 0x13, + }, + .str_desc_size = 12, + .desc_params = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xC796, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2749, + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7CF9, + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1899, + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09, + }, + .frame_type = UCLOGIC_PARAMS_FRAME_DIAL, + }, + /* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */ + { + .name = "frame_type_mouse", + .res = 0, + .str_desc = { + 0x0E, 0x03, + 0xC8, 0xB3, + 0x34, 0x65, + 0x08, + 0x02, + 0xFF, 0x1F, + 0xD8, 0x13, + }, + .str_desc_size = 12, + .desc_params = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363, + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534, + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC, + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF, + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08, + }, + .frame_type = UCLOGIC_PARAMS_FRAME_MOUSE, + }, +}; + +static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_desc_case *t, + char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases, + uclogic_parse_ugee_v2_desc_case_desc); + +static void uclogic_parse_ugee_v2_desc_test(struct kunit *test) +{ + int res; + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; + enum uclogic_params_frame_type frame_type; + const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value; + + res = uclogic_params_parse_ugee_v2_desc(params->str_desc, + params->str_desc_size, + desc_params, + ARRAY_SIZE(desc_params), + &frame_type); + KUNIT_ASSERT_EQ(test, res, params->res); + + if (res) + return; + + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM], + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM]); + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM], + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM]); + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM], + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM]); + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM], + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM]); + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM], + desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM]); + KUNIT_EXPECT_EQ(test, + params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM], + desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]); + KUNIT_EXPECT_EQ(test, params->frame_type, frame_type); +} + +static struct kunit_case hid_uclogic_params_test_cases[] = { + KUNIT_CASE_PARAM(uclogic_parse_ugee_v2_desc_test, + uclogic_parse_ugee_v2_desc_gen_params), + {} +}; + +static struct kunit_suite hid_uclogic_params_test_suite = { + .name = "hid_uclogic_params_test", + .test_cases = hid_uclogic_params_test_cases, +}; + +kunit_test_suite(hid_uclogic_params_test_suite); + +MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index c11fa239e6a2..34fa991e6267 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1057,6 +1057,161 @@ cleanup: } /** + * uclogic_params_parse_ugee_v2_desc - parse the string descriptor containing + * pen and frame parameters returned by UGEE v2 devices. + * + * @str_desc: String descriptor, cannot be NULL. + * @str_desc_size: Size of the string descriptor. + * @desc_params: Output description params list. + * @desc_params_size: Size of the output description params list. + * @frame_type: Output frame type. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc, + size_t str_desc_size, + s32 *desc_params, + size_t desc_params_size, + enum uclogic_params_frame_type *frame_type) +{ + s32 pen_x_lm, pen_y_lm; + s32 pen_x_pm, pen_y_pm; + s32 pen_pressure_lm; + s32 frame_num_buttons; + s32 resolution; + + /* Minimum descriptor length required, maximum seen so far is 14 */ + const int min_str_desc_size = 12; + + if (!str_desc || str_desc_size < min_str_desc_size) + return -EINVAL; + + if (desc_params_size != UCLOGIC_RDESC_PH_ID_NUM) + return -EINVAL; + + pen_x_lm = get_unaligned_le16(str_desc + 2); + pen_y_lm = get_unaligned_le16(str_desc + 4); + frame_num_buttons = str_desc[6]; + *frame_type = str_desc[7]; + pen_pressure_lm = get_unaligned_le16(str_desc + 8); + + resolution = get_unaligned_le16(str_desc + 10); + if (resolution == 0) { + pen_x_pm = 0; + pen_y_pm = 0; + } else { + pen_x_pm = pen_x_lm * 1000 / resolution; + pen_y_pm = pen_y_lm * 1000 / resolution; + } + + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = pen_x_lm; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = pen_x_pm; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = pen_y_lm; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = pen_y_pm; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = pen_pressure_lm; + desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = frame_num_buttons; + + return 0; +} + +/** + * uclogic_params_ugee_v2_init_frame_buttons() - initialize a UGEE v2 frame with + * buttons. + * @p: Parameters to fill in, cannot be NULL. + * @desc_params: Device description params list. + * @desc_params_size: Size of the description params list. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_ugee_v2_init_frame_buttons(struct uclogic_params *p, + const s32 *desc_params, + size_t desc_params_size) +{ + __u8 *rdesc_frame = NULL; + int rc = 0; + + if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM) + return -EINVAL; + + rdesc_frame = uclogic_rdesc_template_apply( + uclogic_rdesc_ugee_v2_frame_btn_template_arr, + uclogic_rdesc_ugee_v2_frame_btn_template_size, + desc_params, UCLOGIC_RDESC_PH_ID_NUM); + if (!rdesc_frame) + return -ENOMEM; + + rc = uclogic_params_frame_init_with_desc(&p->frame_list[0], + rdesc_frame, + uclogic_rdesc_ugee_v2_frame_btn_template_size, + UCLOGIC_RDESC_V1_FRAME_ID); + kfree(rdesc_frame); + return rc; +} + +/** + * uclogic_params_ugee_v2_init_frame_dial() - initialize a UGEE v2 frame with a + * bitmap dial. + * @p: Parameters to fill in, cannot be NULL. + * @desc_params: Device description params list. + * @desc_params_size: Size of the description params list. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_ugee_v2_init_frame_dial(struct uclogic_params *p, + const s32 *desc_params, + size_t desc_params_size) +{ + __u8 *rdesc_frame = NULL; + int rc = 0; + + if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM) + return -EINVAL; + + rdesc_frame = uclogic_rdesc_template_apply( + uclogic_rdesc_ugee_v2_frame_dial_template_arr, + uclogic_rdesc_ugee_v2_frame_dial_template_size, + desc_params, UCLOGIC_RDESC_PH_ID_NUM); + if (!rdesc_frame) + return -ENOMEM; + + rc = uclogic_params_frame_init_with_desc(&p->frame_list[0], + rdesc_frame, + uclogic_rdesc_ugee_v2_frame_dial_template_size, + UCLOGIC_RDESC_V1_FRAME_ID); + kfree(rdesc_frame); + if (rc) + return rc; + + p->frame_list[0].bitmap_dial_byte = 7; + return 0; +} + +/** + * uclogic_params_ugee_v2_init_frame_mouse() - initialize a UGEE v2 frame with a + * mouse. + * @p: Parameters to fill in, cannot be NULL. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p) +{ + int rc = 0; + + if (!p) + return -EINVAL; + + rc = uclogic_params_frame_init_with_desc(&p->frame_list[1], + uclogic_rdesc_ugee_v2_frame_mouse_template_arr, + uclogic_rdesc_ugee_v2_frame_mouse_template_size, + UCLOGIC_RDESC_V1_FRAME_ID); + return rc; +} + +/** * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by * discovering their parameters. * @@ -1084,9 +1239,8 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, const int str_desc_len = 12; __u8 *str_desc = NULL; __u8 *rdesc_pen = NULL; - __u8 *rdesc_frame = NULL; s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; - s32 resolution; + enum uclogic_params_frame_type frame_type; __u8 magic_arr[] = { 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1100,6 +1254,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + + if (bInterfaceNumber == 0) { + rc = uclogic_params_ugee_v2_init_frame_mouse(&p); + if (rc) + goto cleanup; + + goto output; + } + if (bInterfaceNumber != 2) { uclogic_params_init_invalid(&p); goto output; @@ -1128,25 +1291,13 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, goto output; } - desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = - get_unaligned_le16(str_desc + 2); - desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = - get_unaligned_le16(str_desc + 4); - desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6]; - desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = - get_unaligned_le16(str_desc + 8); - resolution = get_unaligned_le16(str_desc + 10); - if (resolution == 0) { - desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; - desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; - } else { - desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = - desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / - resolution; - desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = - desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / - resolution; - } + rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len, + desc_params, + ARRAY_SIZE(desc_params), + &frame_type); + if (rc) + goto cleanup; + kfree(str_desc); str_desc = NULL; @@ -1167,24 +1318,21 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; /* Initialize the frame interface */ - rdesc_frame = uclogic_rdesc_template_apply( - uclogic_rdesc_ugee_v2_frame_btn_template_arr, - uclogic_rdesc_ugee_v2_frame_btn_template_size, - desc_params, ARRAY_SIZE(desc_params)); - if (!rdesc_frame) { - rc = -ENOMEM; - goto cleanup; + switch (frame_type) { + case UCLOGIC_PARAMS_FRAME_DIAL: + case UCLOGIC_PARAMS_FRAME_MOUSE: + rc = uclogic_params_ugee_v2_init_frame_dial(&p, desc_params, + ARRAY_SIZE(desc_params)); + break; + case UCLOGIC_PARAMS_FRAME_BUTTONS: + default: + rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params, + ARRAY_SIZE(desc_params)); + break; } - rc = uclogic_params_frame_init_with_desc(&p.frame_list[0], - rdesc_frame, - uclogic_rdesc_ugee_v2_frame_btn_template_size, - UCLOGIC_RDESC_V1_FRAME_ID); - kfree(rdesc_frame); - if (rc) { - uclogic_params_init_invalid(&p); - goto output; - } + if (rc) + goto cleanup; output: /* Output parameters */ @@ -1433,7 +1581,11 @@ int uclogic_params_init(struct uclogic_params *params, } break; case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_PARBLO_A610_PRO): + case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): + case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S): rc = uclogic_params_ugee_v2_init(&p, hdev); if (rc != 0) goto cleanup; @@ -1517,3 +1669,7 @@ cleanup: uclogic_params_cleanup(&p); return rc; } + +#ifdef CONFIG_HID_KUNIT_TEST +#include "hid-uclogic-params-test.c" +#endif diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index 5bef8daaa607..a97477c02ff8 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -29,6 +29,16 @@ enum uclogic_params_pen_inrange { UCLOGIC_PARAMS_PEN_INRANGE_NONE, }; +/* Types of frames */ +enum uclogic_params_frame_type { + /* Frame with buttons */ + UCLOGIC_PARAMS_FRAME_BUTTONS = 0, + /* Frame with buttons and a dial */ + UCLOGIC_PARAMS_FRAME_DIAL, + /* Frame with buttons and a mouse (shaped as a dial + touchpad) */ + UCLOGIC_PARAMS_FRAME_MOUSE, +}; + /* * Pen report's subreport data. */ diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c index ebebffef5f8a..3971a0854c3e 100644 --- a/drivers/hid/hid-uclogic-rdesc-test.c +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -97,7 +97,7 @@ static const __u8 template_params_none[] = { static struct uclogic_template_case uclogic_template_cases[] = { { - .name = "Empty template", + .name = "empty_template", .template = template_empty, .template_size = sizeof(template_empty), .param_list = params_pen_all, @@ -105,7 +105,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = template_empty, }, { - .name = "Template smaller than the placeholder", + .name = "template_smaller_than_the_placeholder", .template = template_small, .template_size = sizeof(template_small), .param_list = params_pen_all, @@ -113,7 +113,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = template_small, }, { - .name = "No placeholder", + .name = "no_placeholder", .template = template_no_ph, .template_size = sizeof(template_no_ph), .param_list = params_pen_all, @@ -121,7 +121,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = template_no_ph, }, { - .name = "Pen placeholder at the end, without ID", + .name = "pen_placeholder_at_the_end_without_id", .template = template_pen_ph_end, .template_size = sizeof(template_pen_ph_end), .param_list = params_pen_all, @@ -129,7 +129,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = template_pen_ph_end, }, { - .name = "Frame button placeholder at the end, without ID", + .name = "frame_button_placeholder_at_the_end_without_id", .template = template_btn_ph_end, .template_size = sizeof(template_btn_ph_end), .param_list = params_frame_all, @@ -137,7 +137,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = template_btn_ph_end, }, { - .name = "All params present in the pen template", + .name = "all_params_present_in_the_pen_template", .template = template_pen_all_params, .template_size = sizeof(template_pen_all_params), .param_list = params_pen_all, @@ -145,7 +145,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = expected_pen_all_params, }, { - .name = "All params present in the frame template", + .name = "all_params_present_in_the_frame_template", .template = template_frame_all_params, .template_size = sizeof(template_frame_all_params), .param_list = params_frame_all, @@ -153,7 +153,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = expected_frame_all_params, }, { - .name = "Some params present in the pen template (complete param list)", + .name = "some_params_present_in_the_pen_template_with_complete_param_list", .template = template_pen_some_params, .template_size = sizeof(template_pen_some_params), .param_list = params_pen_all, @@ -161,7 +161,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = expected_pen_some_params, }, { - .name = "Some params present in the pen template (incomplete param list)", + .name = "some_params_present_in_the_pen_template_with_incomplete_param_list", .template = template_pen_some_params, .template_size = sizeof(template_pen_some_params), .param_list = params_pen_some, @@ -169,7 +169,7 @@ static struct uclogic_template_case uclogic_template_cases[] = { .expected = expected_pen_some_params, }, { - .name = "No params present in the template", + .name = "no_params_present_in_the_template", .template = template_params_none, .template_size = sizeof(template_params_none), .param_list = params_pen_some, @@ -208,7 +208,7 @@ static struct kunit_case hid_uclogic_rdesc_test_cases[] = { }; static struct kunit_suite hid_uclogic_rdesc_test_suite = { - .name = "hid-uclogic-rdesc-test", + .name = "hid_uclogic_rdesc_test", .test_cases = hid_uclogic_rdesc_test_cases, }; diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 3d68e8b0784d..4bd54c4fb5b0 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -961,6 +961,80 @@ const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = { const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size = sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr); +/* Fixed report descriptor template for UGEE v2 frame reports (dial) */ +const __u8 uclogic_rdesc_ugee_v2_frame_dial_template_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, + /* Report ID, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x39, /* Usage (Tablet Function Keys), */ + 0xA0, /* Collection (Physical), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x08, /* Report Count (8), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + UCLOGIC_RDESC_FRAME_PH_BTN, + /* Usage Maximum (PLACEHOLDER), */ + 0x95, 0x0A, /* Report Count (10), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x38, /* Usage (Wheel), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0xFF, /* Logical Minimum (-1), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size = + sizeof(uclogic_rdesc_ugee_v2_frame_dial_template_arr); + +/* Fixed report descriptor template for UGEE v2 frame reports (mouse) */ +const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x02, /* Usage (Mouse), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x01, /* Report ID (1), */ + 0x05, 0x01, /* Usage Page (Pointer), */ + 0xA0, /* Collection (Physical), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x02, /* Usage Maximum (02h), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Generic Desktop), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x02, /* Report Count (2), */ + 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */ + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size = + sizeof(uclogic_rdesc_ugee_v2_frame_mouse_template_arr); + /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ @@ -1113,7 +1187,7 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, memcmp(p, pen_head, sizeof(pen_head)) == 0 && p[sizeof(pen_head)] < param_num) { v = param_list[p[sizeof(pen_head)]]; - put_unaligned(cpu_to_le32(v), (s32 *)p); + put_unaligned((__force u32)cpu_to_le32(v), (s32 *)p); p += sizeof(pen_head) + 1; } else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 && p[sizeof(btn_head)] < param_num) { diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 86e64a9ee6bd..0502a0656496 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -169,6 +169,14 @@ extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[]; extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size; +/* Fixed report descriptor template for UGEE v2 frame reports (dial) */ +extern const __u8 uclogic_rdesc_ugee_v2_frame_dial_template_arr[]; +extern const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size; + +/* Fixed report descriptor template for UGEE v2 frame reports (mouse) */ +extern const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[]; +extern const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size; + /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; extern const size_t uclogic_rdesc_ugee_ex07_frame_size; diff --git a/drivers/hid/hid-vivaldi-common.c b/drivers/hid/hid-vivaldi-common.c index 8b3e515d0f06..b0af2be94895 100644 --- a/drivers/hid/hid-vivaldi-common.c +++ b/drivers/hid/hid-vivaldi-common.c @@ -116,25 +116,26 @@ static struct attribute *vivaldi_sysfs_attrs[] = { NULL }; -static const struct attribute_group vivaldi_attribute_group = { - .attrs = vivaldi_sysfs_attrs, -}; - -/** - * vivaldi_input_configured - Complete initialization of device using vivaldi map - * @hdev: HID device to which vivaldi attributes should be attached - * @hidinput: HID input device (unused) - */ -int vivaldi_input_configured(struct hid_device *hdev, - struct hid_input *hidinput) +static umode_t vivaldi_is_visible(struct kobject *kobj, struct attribute *attr, + int n) { + struct hid_device *hdev = to_hid_device(kobj_to_dev(kobj)); struct vivaldi_data *data = hid_get_drvdata(hdev); if (!data->num_function_row_keys) return 0; - - return devm_device_add_group(&hdev->dev, &vivaldi_attribute_group); + return attr->mode; } -EXPORT_SYMBOL_GPL(vivaldi_input_configured); + +static const struct attribute_group vivaldi_attribute_group = { + .attrs = vivaldi_sysfs_attrs, + .is_visible = vivaldi_is_visible, +}; + +const struct attribute_group *vivaldi_attribute_groups[] = { + &vivaldi_attribute_group, + NULL, +}; +EXPORT_SYMBOL_GPL(vivaldi_attribute_groups); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-vivaldi-common.h b/drivers/hid/hid-vivaldi-common.h index d42e82d77825..ba9adfa08a2d 100644 --- a/drivers/hid/hid-vivaldi-common.h +++ b/drivers/hid/hid-vivaldi-common.h @@ -4,13 +4,11 @@ struct hid_device; struct hid_field; -struct hid_input; struct hid_usage; void vivaldi_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage); -int vivaldi_input_configured(struct hid_device *hdev, - struct hid_input *hidinput); +extern const struct attribute_group *vivaldi_attribute_groups[]; #endif /* _HID_VIVALDI_COMMON_H */ diff --git a/drivers/hid/hid-vivaldi.c b/drivers/hid/hid-vivaldi.c index 3a979123e7d3..cda5938fb070 100644 --- a/drivers/hid/hid-vivaldi.c +++ b/drivers/hid/hid-vivaldi.c @@ -45,7 +45,9 @@ static struct hid_driver hid_vivaldi = { .id_table = vivaldi_table, .probe = vivaldi_probe, .feature_mapping = vivaldi_feature_mapping, - .input_configured = vivaldi_input_configured, + .driver = { + .dev_groups = vivaldi_attribute_groups, + }, }; module_hid_driver(hid_vivaldi); diff --git a/drivers/hid/hid-vrc2.c b/drivers/hid/hid-vrc2.c new file mode 100644 index 000000000000..80a2b7ef5e66 --- /dev/null +++ b/drivers/hid/hid-vrc2.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for VRC-2 2-axis Car controller + * + * Copyright (C) 2022 Marcus Folkesson <marcus.folkesson@gmail.com> + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> + +/* + * VID/PID are probably "borrowed", so keep them locally and + * do not populate hid-ids.h with those. + */ +#define USB_VENDOR_ID_VRC2 (0x07c0) +#define USB_DEVICE_ID_VRC2 (0x1125) + +static __u8 vrc2_rdesc_fixed[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x07, // Logical Maximum (2047) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x81, 0x03, // Input (Cnst,Var,Abs) + 0xC0, // End Collection +}; + +static __u8 *vrc2_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + hid_info(hdev, "fixing up VRC-2 report descriptor\n"); + *rsize = sizeof(vrc2_rdesc_fixed); + return vrc2_rdesc_fixed; +} + +static int vrc2_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + /* + * The device gives us 2 separate USB endpoints. + * One of those (the one with report descriptor size of 23) is just bogus so ignore it + */ + if (hdev->dev_rsize == 23) + return -ENODEV; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + return 0; +} + +static const struct hid_device_id vrc2_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_VRC2, USB_DEVICE_ID_VRC2) }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(hid, vrc2_devices); + +static struct hid_driver vrc2_driver = { + .name = "vrc2", + .id_table = vrc2_devices, + .report_fixup = vrc2_report_fixup, + .probe = vrc2_probe, +}; +module_hid_driver(vrc2_driver); + +MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>"); +MODULE_DESCRIPTION("HID driver for VRC-2 2-axis Car controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 95cefae47adf..0667b6022c3b 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -1036,7 +1036,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", client->name, (u16)hid->vendor, (u16)hid->product); - strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); + strscpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 4490e2f7252a..be4c731aaa65 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1381,7 +1381,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * hid->type = HID_TYPE_USBNONE; if (dev->manufacturer) - strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); + strscpy(hid->name, dev->manufacturer, sizeof(hid->name)); if (dev->product) { if (dev->manufacturer) diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index b4b007c4beb6..c439ed2f16db 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -294,7 +294,7 @@ static int usb_kbd_probe(struct usb_interface *iface, spin_lock_init(&kbd->leds_lock); if (dev->manufacturer) - strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); + strscpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); if (dev->product) { if (dev->manufacturer) diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index fb1d7d1f6999..3fd93c2e4f4a 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -142,7 +142,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i mouse->dev = input_dev; if (dev->manufacturer) - strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); + strscpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); if (dev->product) { if (dev->manufacturer) diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 3f8b24a57014..4da50e19808e 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * drivers/input/tablet/wacom.h - * * USB Wacom tablet support * * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz> @@ -78,10 +76,9 @@ * - integration of the Bluetooth devices */ -/* - */ #ifndef WACOM_H #define WACOM_H + #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 194a2e327591..634263e4556b 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1,13 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * drivers/input/tablet/wacom_sys.c - * * USB Wacom tablet support - system specific code */ -/* - */ - #include "wacom_wac.h" #include "wacom.h" #include <linux/input/mt.h> @@ -2226,7 +2221,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) } else if (strstr(product_name, "Wacom") || strstr(product_name, "wacom") || strstr(product_name, "WACOM")) { - strlcpy(name, product_name, sizeof(name)); + strscpy(name, product_name, sizeof(name)); } else { snprintf(name, sizeof(name), "Wacom %s", product_name); } @@ -2244,7 +2239,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) if (name[strlen(name)-1] == ' ') name[strlen(name)-1] = '\0'; } else { - strlcpy(name, features->name, sizeof(name)); + strscpy(name, features->name, sizeof(name)); } snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s", @@ -2509,7 +2504,7 @@ static void wacom_wireless_work(struct work_struct *work) goto fail; } - strlcpy(wacom_wac->name, wacom_wac1->name, + strscpy(wacom_wac->name, wacom_wac1->name, sizeof(wacom_wac->name)); error = wacom_initialize_battery(wacom); if (error) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index d049239256a2..77486962a773 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1,13 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * drivers/input/tablet/wacom_wac.c - * * USB Wacom tablet support - Wacom specific code */ -/* - */ - #include "wacom_wac.h" #include "wacom.h" #include <linux/input/mt.h> @@ -713,11 +708,14 @@ static int wacom_intuos_get_tool_type(int tool_id) case 0x802: /* Intuos4/5 13HD/24HD General Pen */ case 0x8e2: /* IntuosHT2 pen */ case 0x022: + case 0x200: /* Pro Pen 3 */ + case 0x04200: /* Pro Pen 3 */ case 0x10842: /* MobileStudio Pro Pro Pen slim */ case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ case 0x16802: /* Cintiq 13HD Pro Pen */ case 0x18802: /* DTH2242 Pen */ case 0x10802: /* Intuos4/5 13HD/24HD General Pen */ + case 0x80842: /* Intuos Pro and Cintiq Pro 3D Pen */ tool_type = BTN_TOOL_PEN; break; @@ -4875,6 +4873,10 @@ static const struct wacom_features wacom_features_0x3c6 = static const struct wacom_features wacom_features_0x3c8 = { "Wacom Intuos BT M", 21600, 13500, 4095, 63, INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; +static const struct wacom_features wacom_features_0x3dd = + { "Wacom Intuos Pro S", 31920, 19950, 8191, 63, + INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, + .touch_max = 10 }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; @@ -5050,6 +5052,7 @@ const struct hid_device_id wacom_ids[] = { { BT_DEVICE_WACOM(0x393) }, { BT_DEVICE_WACOM(0x3c6) }, { BT_DEVICE_WACOM(0x3c8) }, + { BT_DEVICE_WACOM(0x3dd) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index fef1538005b5..5ca6c06d143b 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * drivers/input/tablet/wacom_wac.h - */ + #ifndef WACOM_WAC_H #define WACOM_WAC_H diff --git a/include/linux/hid.h b/include/linux/hid.h index 4363a63b9775..8677ae38599e 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -314,15 +314,6 @@ struct hid_item { #define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065 #define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076 -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -#define HID_REPORT_TYPES 3 /* * HID connect requests @@ -509,7 +500,7 @@ struct hid_report { struct list_head hidinput_list; struct list_head field_entry_list; /* ordered list of input fields */ unsigned int id; /* id of this report */ - unsigned int type; /* report type */ + enum hid_report_type type; /* report type */ unsigned int application; /* application usage for this report */ struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ struct hid_field_entry *field_entries; /* allocated memory of input field_entry */ @@ -658,6 +649,8 @@ struct hid_device { /* device report descriptor */ struct list_head debug_list; spinlock_t debug_list_lock; wait_queue_head_t debug_wait; + + unsigned int id; /* system unique id */ }; #define to_hid_device(pdev) \ @@ -924,20 +917,21 @@ extern int hidinput_connect(struct hid_device *hid, unsigned int force); extern void hidinput_disconnect(struct hid_device *); int hid_set_field(struct hid_field *, unsigned, __s32); -int hid_input_report(struct hid_device *, int type, u8 *, u32, int); +int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, + int interrupt); struct hid_field *hidinput_get_led_field(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid); __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code); void hid_output_report(struct hid_report *report, __u8 *data); -int __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype); +int __hid_request(struct hid_device *hid, struct hid_report *rep, enum hid_class_request reqtype); u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); struct hid_device *hid_allocate_device(void); struct hid_report *hid_register_report(struct hid_device *device, - unsigned int type, unsigned int id, + enum hid_report_type type, unsigned int id, unsigned int application); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); struct hid_report *hid_validate_values(struct hid_device *hid, - unsigned int type, unsigned int id, + enum hid_report_type type, unsigned int id, unsigned int field_index, unsigned int report_counts); @@ -1106,10 +1100,11 @@ void hid_hw_stop(struct hid_device *hdev); int __must_check hid_hw_open(struct hid_device *hdev); void hid_hw_close(struct hid_device *hdev); void hid_hw_request(struct hid_device *hdev, - struct hid_report *report, int reqtype); + struct hid_report *report, enum hid_class_request reqtype); int hid_hw_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, - size_t len, unsigned char rtype, int reqtype); + size_t len, enum hid_report_type rtype, + enum hid_class_request reqtype); int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len); /** @@ -1137,7 +1132,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level) * @reqtype: hid request type */ static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle, - int reqtype) + enum hid_class_request reqtype) { if (hdev->ll_driver->idle) return hdev->ll_driver->idle(hdev, report, idle, reqtype); @@ -1182,8 +1177,8 @@ static inline u32 hid_report_len(struct hid_report *report) return DIV_ROUND_UP(report->size, 8) + (report->id > 0); } -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, - int interrupt); +int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, + int interrupt); /* HID quirks API */ unsigned long hid_lookup_quirk(const struct hid_device *hdev); diff --git a/include/uapi/linux/hid.h b/include/uapi/linux/hid.h index b34492a87a8a..a4dcb34386e3 100644 --- a/include/uapi/linux/hid.h +++ b/include/uapi/linux/hid.h @@ -43,15 +43,29 @@ #define USB_INTERFACE_PROTOCOL_MOUSE 2 /* + * HID report types --- Ouch! HID spec says 1 2 3! + */ + +enum hid_report_type { + HID_INPUT_REPORT = 0, + HID_OUTPUT_REPORT = 1, + HID_FEATURE_REPORT = 2, + + HID_REPORT_TYPES, +}; + +/* * HID class requests */ -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B +enum hid_class_request { + HID_REQ_GET_REPORT = 0x01, + HID_REQ_GET_IDLE = 0x02, + HID_REQ_GET_PROTOCOL = 0x03, + HID_REQ_SET_REPORT = 0x09, + HID_REQ_SET_IDLE = 0x0A, + HID_REQ_SET_PROTOCOL = 0x0B, +}; /* * HID class descriptor types |