mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
hid-for-linus-2026061601
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEL65usyKPHcrRDEicpmLzj2vtYEkFAmoxq94ACgkQpmLzj2vt
YElr1A//RPXn3om4Sm5QeIcbIFHrdVx6Un8QcXVaNSqL8XUB7yMCbsH+zD7NmWSP
U4wX9bDZ0F8/1gkQh80HuGDEEErSmzAQk8+iE3mhUTXmLmyPn7bgHClMXVmKD1UO
74f6+57RV7Y0Uo/cgna9hLr3kuSCR5+y81f9esWoXSz8j6BNzml6KyCNcNbbnYlk
RmS6c5MJ15KxnY593HKr04jWqC1zs++pdcAOmZF3gnwTf7X+Pl3hgP53jCQeAJqH
AGbXc8N09Nc+JBEJ9zUIgwpU0DwnJRe+/LptIWNGebpSW2/jqfXWabrHjpaXekuX
6hf+/bnkeoIKDQGIAXSFuqEBsP0WofEbAvCix0+QVEz3MBDtsR6/3h3q+/hbNEgJ
KrAO7rEHTEEOKPvYiIwQ6cMPAlNRF178k4Havy2EZaaT8w0v9/eovYRIR1J2H/34
0D7pRb+pyxV0vzuHosa7EKRTTga+8LOwWxLB5lJnG5UhSBUYghihGM6T8pCjBCw5
BuhcVPpGRT6kreOAIR82sUxfOZHcq6g8rj64iHofPNiPlAr/qkehhHGJ2sBLzeMm
CPSmYrI0hwULldRunR9/JBMBC44fzfhoRhcQZE1QaJbRu7KYPMWhRPRR8nNR6oEc
xDnbllexgSya9yAjKZ8mJKb4ywIFUrqpC0xacQmJbZmaXkTX8mI=
=O/MI
-----END PGP SIGNATURE-----
Merge tag 'hid-for-linus-2026061601' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina:
"Core:
- semantic cleanup fixes for 'hid_device_id::driver_data' (Pawel
Zalewski)
Multitouch:
- UX improvement fixes for Yoga Book 9 (Dave Carey)
Logitech:
- fix for high resolution scrolling for Logitech HID++ 2.0 devices
(Lauri Saurus)
CP2112:
- fix for cp2112 firmware-based speed configuration, if available
(Danny Kaehn)
Wacom:
- memory corruption and scheduling while atomic and error fixes and
error handling fixes (Jinmo Yang, Myeonghun Pak)
New device support:
- OneXPlayer (Derek J. Clark)
- HORI Wireless Switch Pad (Hector Zelaya)
- Rakk Dasig X (Karl Cayme)
And other assorted small fixes and device ID additions"
* tag 'hid-for-linus-2026061601' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (39 commits)
HID: hidpp: fix potential UAF in hidpp_connect_event()
HID: logitech-hidpp: sync wheel multiplier on wheel mode changes
HID: intel-thc-hid: intel-quickspi: reset touch IC on system resume
HID: uhid: convert to hid_safe_input_report()
HID: hid-goodix-spi: validate report size to prevent stack buffer overflow
HID: nintendo: add support for HORI Wireless Switch Pad
HID: multitouch: Honor ContactCount for Yoga Book 9 to suppress ghost contacts
HID: pidff: Use correct effect type in effect update
HID: wacom: stop hardware after post-start probe failures
HID: core: demote warning to debug level
HID: lenovo: Use KEY_PERFORMANCE capability for ThinkPad X12 Tab Gen 2
HID: lenovo: Add support for ThinkPad X13 Folio keyboard
HID: cp2112: Configure I2C bus speed from firmware
HID: cp2112: Add fwnode support
HID: hid-lenovo-go: cancel cfg_setup work in hid_go_cfg_remove()
HID: Input: Add battery list cleanup with devm action
HID: logitech-hidpp: remove excess kernel-doc member in hidpp_scroll_counter
HID: wacom: use cleanup.h for wacom_wac_queue_flush() buffer management
HID: wacom: use GFP_ATOMIC in wacom_wac_queue_flush()
HID: wacom: fix slab-out-of-bounds write in wacom_wac_queue_insert
...
This commit is contained in:
commit
b7556c8e71
|
|
@ -20050,6 +20050,12 @@ S: Maintained
|
|||
F: drivers/mtd/nand/onenand/
|
||||
F: include/linux/mtd/onenand*.h
|
||||
|
||||
ONEXPLAYER HID DRIVER
|
||||
M: Derek J. Clark <derekjohn.clark@gmail.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-oxp.c
|
||||
|
||||
ONEXPLAYER PLATFORM EC DRIVER
|
||||
M: Antheas Kapenekakis <lkml@antheas.dev>
|
||||
M: Derek John Clark <derekjohn.clark@gmail.com>
|
||||
|
|
|
|||
|
|
@ -766,6 +766,15 @@ config HID_MEGAWORLD_FF
|
|||
Say Y here if you have a Mega World based game controller and want
|
||||
to have force feedback support for it.
|
||||
|
||||
config HID_RAKK
|
||||
tristate "Rakk support"
|
||||
help
|
||||
Support for Rakk gaming peripherals.
|
||||
|
||||
Fixes the HID report descriptor of the Rakk Dasig X mouse,
|
||||
which declares USAGE_MAXIMUM=3 (buttons 1-3) while actually
|
||||
sending 5 button bits. This causes side buttons to be ignored.
|
||||
|
||||
config HID_REDRAGON
|
||||
tristate "Redragon keyboards"
|
||||
help
|
||||
|
|
@ -896,6 +905,19 @@ config HID_ORTEK
|
|||
- Ortek WKB-2000
|
||||
- Skycable wireless presenter
|
||||
|
||||
config HID_OXP
|
||||
tristate "OneXPlayer handheld controller configuration support"
|
||||
depends on USB_HID
|
||||
depends on LEDS_CLASS
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
depends on DMI
|
||||
help
|
||||
Say Y here if you would like to enable support for OneXPlayer handheld
|
||||
devices that come with RGB LED rings around the joysticks and macro buttons.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called hid-oxp.
|
||||
|
||||
config HID_PANTHERLORD
|
||||
tristate "Pantherlord/GreenAsia game controller"
|
||||
help
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ obj-$(CONFIG_HID_NTI) += hid-nti.o
|
|||
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
|
||||
obj-$(CONFIG_HID_NVIDIA_SHIELD) += hid-nvidia-shield.o
|
||||
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
|
||||
obj-$(CONFIG_HID_OXP) += hid-oxp.o
|
||||
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
|
||||
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
|
||||
obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o
|
||||
|
|
@ -115,6 +116,7 @@ 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_RAKK) += hid-rakk.o
|
||||
obj-$(CONFIG_HID_RAPOO) += hid-rapoo.o
|
||||
obj-$(CONFIG_HID_RAZER) += hid-razer.o
|
||||
obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o
|
||||
|
|
|
|||
87
drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c
Normal file
87
drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "vmlinux.h"
|
||||
#include "hid_bpf.h"
|
||||
#include "hid_bpf_helpers.h"
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
/*
|
||||
* Huion Inspiroy Frego M Pen Tablet
|
||||
* Model L610
|
||||
* 256c:8251 (Bluetooth)
|
||||
* 256c:2012 (USB)
|
||||
*/
|
||||
#define VID_HUION 0x256C
|
||||
#define PID_INSPIROY_FREGO_M 0x8251
|
||||
#define PID_L610 0x2012
|
||||
|
||||
#define PEN_RDESC_SIZE 125
|
||||
#define SECONDARY_SWITCH_OFFSET 17
|
||||
|
||||
HID_BPF_CONFIG(
|
||||
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_FREGO_M),
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_L610)
|
||||
);
|
||||
|
||||
/*
|
||||
* The pen descriptor reports the second side button as Secondary Tip Switch
|
||||
* instead of Secondary Barrel Switch.
|
||||
*
|
||||
* Relevant part of the original pen report descriptor:
|
||||
*
|
||||
* 0x09, 0x42, // Usage (Tip Switch) 12
|
||||
* 0x09, 0x44, // Usage (Barrel Switch) 14
|
||||
* 0x09, 0x43, // Usage (Secondary Tip Switch) 16 <- change to 0x5a
|
||||
* 0x09, 0x3c, // Usage (Invert) 18
|
||||
* 0x09, 0x45, // Usage (Eraser) 20
|
||||
* 0x15, 0x00, // Logical Minimum (0) 22
|
||||
* 0x25, 0x01, // Logical Maximum (1) 24
|
||||
*/
|
||||
SEC(HID_BPF_RDESC_FIXUP)
|
||||
int BPF_PROG(fix_secondary_barrel_rdesc, struct hid_bpf_ctx *hctx)
|
||||
{
|
||||
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
|
||||
|
||||
if (!data)
|
||||
return 0; /* EPERM check */
|
||||
|
||||
if (hctx->size != PEN_RDESC_SIZE)
|
||||
return 0;
|
||||
|
||||
if (data[0] != 0x05 || data[1] != 0x0d || /* Usage Page (Digitizers) */
|
||||
data[2] != 0x09 || data[3] != 0x02 || /* Usage (Pen) */
|
||||
data[16] != 0x09 ||
|
||||
data[SECONDARY_SWITCH_OFFSET] != 0x43) /* Secondary Tip Switch */
|
||||
return 0;
|
||||
|
||||
data[SECONDARY_SWITCH_OFFSET] = 0x5a;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HID_BPF_OPS(fix_secondary_barrel) = {
|
||||
.hid_rdesc_fixup = (void *)fix_secondary_barrel_rdesc,
|
||||
};
|
||||
|
||||
SEC("syscall")
|
||||
int probe(struct hid_bpf_probe_args *ctx)
|
||||
{
|
||||
ctx->retval = ctx->rdesc_size != PEN_RDESC_SIZE;
|
||||
if (ctx->retval) {
|
||||
ctx->retval = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->rdesc[0] != 0x05 || ctx->rdesc[1] != 0x0d || /* Usage Page (Digitizers) */
|
||||
ctx->rdesc[2] != 0x09 || ctx->rdesc[3] != 0x02 || /* Usage (Pen) */
|
||||
ctx->rdesc[16] != 0x09 ||
|
||||
ctx->rdesc[SECONDARY_SWITCH_OFFSET] != 0x43) { /* Secondary Tip Switch */
|
||||
ctx->retval = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->retval = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
@ -27,7 +27,8 @@ static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
const struct hid_device_id *id = hid_get_drvdata(hdev);
|
||||
unsigned long quirks = id->driver_data;
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER ||
|
||||
!(quirks & BELKIN_WKBD))
|
||||
|
|
@ -48,7 +49,7 @@ static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
unsigned long quirks = id->driver_data;
|
||||
int ret;
|
||||
|
||||
hid_set_drvdata(hdev, (void *)quirks);
|
||||
hid_set_drvdata(hdev, (void *)id);
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,18 @@
|
|||
#include <linux/usb/ch9.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
/**
|
||||
* enum cp2112_child_acpi_cell_addrs - Child ACPI addresses for CP2112 sub-functions
|
||||
* Note that the enum values are explicitly defined, as this defines the interface
|
||||
* between ACPI and Linux
|
||||
* @CP2112_I2C_ADR: Address for I2C node
|
||||
* @CP2112_GPIO_ADR: Address for GPIO node
|
||||
*/
|
||||
enum cp2112_child_acpi_cell_addrs {
|
||||
CP2112_I2C_ADR = 0,
|
||||
CP2112_GPIO_ADR = 1,
|
||||
};
|
||||
|
||||
#define CP2112_REPORT_MAX_LENGTH 64
|
||||
#define CP2112_GPIO_CONFIG_LENGTH 5
|
||||
#define CP2112_GPIO_GET_LENGTH 2
|
||||
|
|
@ -1208,7 +1220,11 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
struct cp2112_device *dev;
|
||||
u8 buf[3];
|
||||
struct cp2112_smbus_config_report config;
|
||||
struct fwnode_handle *cp2112_fwnode;
|
||||
struct fwnode_handle *child;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct i2c_timings timings;
|
||||
u32 addr;
|
||||
int ret;
|
||||
|
||||
dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
|
|
@ -1226,6 +1242,28 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
cp2112_fwnode = dev_fwnode(&hdev->dev);
|
||||
if (is_acpi_device_node(cp2112_fwnode)) {
|
||||
fwnode_for_each_child_node(cp2112_fwnode, child) {
|
||||
ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
switch (addr) {
|
||||
case CP2112_I2C_ADR:
|
||||
device_set_node(&dev->adap.dev, child);
|
||||
break;
|
||||
case CP2112_GPIO_ADR:
|
||||
dev->gc.fwnode = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (is_of_node(cp2112_fwnode)) {
|
||||
child = fwnode_get_named_child_node(cp2112_fwnode, "i2c");
|
||||
device_set_node(&dev->adap.dev, child);
|
||||
fwnode_handle_put(child);
|
||||
}
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
|
|
@ -1271,6 +1309,9 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto err_power_normal;
|
||||
}
|
||||
|
||||
i2c_parse_fw_timings(&dev->adap.dev, &timings, true);
|
||||
|
||||
config.clock_speed = cpu_to_be32(timings.bus_freq_hz);
|
||||
config.retry_time = cpu_to_be16(1);
|
||||
|
||||
ret = cp2112_hid_output(hdev, (u8 *)&config, sizeof(config),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
|
||||
#define VA_INVAL_LOGICAL_BOUNDARY 0x08
|
||||
|
||||
struct cp_device {
|
||||
unsigned long quirks;
|
||||
};
|
||||
|
||||
/*
|
||||
* Some USB barcode readers from cypress have usage min and usage max in
|
||||
* the wrong order
|
||||
|
|
@ -70,7 +74,8 @@ static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
static const __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
const struct cp_device *cp_device = hid_get_drvdata(hdev);
|
||||
unsigned long quirks = cp_device->quirks;
|
||||
|
||||
if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
|
||||
rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
|
||||
|
|
@ -84,7 +89,8 @@ static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
const struct cp_device *cp_device = hid_get_drvdata(hdev);
|
||||
unsigned long quirks = cp_device->quirks;
|
||||
|
||||
if (!(quirks & CP_2WHEEL_MOUSE_HACK))
|
||||
return 0;
|
||||
|
|
@ -100,22 +106,21 @@ static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|||
static int cp_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
struct cp_device *cp_device = hid_get_drvdata(hdev);
|
||||
|
||||
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
|
||||
!usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
|
||||
!usage->type || !(cp_device->quirks & CP_2WHEEL_MOUSE_HACK))
|
||||
return 0;
|
||||
|
||||
if (usage->hid == 0x00090005) {
|
||||
if (value)
|
||||
quirks |= CP_2WHEEL_MOUSE_HACK_ON;
|
||||
cp_device->quirks |= CP_2WHEEL_MOUSE_HACK_ON;
|
||||
else
|
||||
quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
|
||||
hid_set_drvdata(hdev, (void *)quirks);
|
||||
cp_device->quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
|
||||
if (usage->code == REL_WHEEL && (cp_device->quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
|
||||
struct input_dev *input = field->hidinput->input;
|
||||
|
||||
input_event(input, usage->type, REL_HWHEEL, value);
|
||||
|
|
@ -127,10 +132,17 @@ static int cp_event(struct hid_device *hdev, struct hid_field *field,
|
|||
|
||||
static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
unsigned long quirks = id->driver_data;
|
||||
int ret;
|
||||
struct cp_device *cp_device;
|
||||
|
||||
hid_set_drvdata(hdev, (void *)quirks);
|
||||
cp_device = devm_kzalloc(&hdev->dev, sizeof(*cp_device), GFP_KERNEL);
|
||||
|
||||
if (!cp_device)
|
||||
return -ENOMEM;
|
||||
|
||||
cp_device->quirks = id->driver_data;
|
||||
|
||||
hid_set_drvdata(hdev, cp_device);
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
|
||||
const struct hid_device_id *id = hid_get_drvdata(hdev);
|
||||
unsigned long hdev_type = id->driver_data;
|
||||
|
||||
if (hdev_type == GFRM100) {
|
||||
if (usage->hid == (HID_UP_CONSUMER | 0x4)) {
|
||||
|
|
@ -50,7 +51,8 @@ static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
u8 *data, int size)
|
||||
{
|
||||
unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev);
|
||||
const struct hid_device_id *id = hid_get_drvdata(hdev);
|
||||
unsigned long hdev_type = id->driver_data;
|
||||
int ret = 0;
|
||||
|
||||
if (hdev_type != GFRM100)
|
||||
|
|
@ -99,7 +101,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
{
|
||||
int ret;
|
||||
|
||||
hid_set_drvdata(hdev, (void *) id->driver_data);
|
||||
hid_set_drvdata(hdev, (void *)id);
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -520,6 +520,9 @@ static int goodix_hid_set_raw_report(struct hid_device *hid,
|
|||
memcpy(tmp_buf + tx_len, args, args_len);
|
||||
tx_len += args_len;
|
||||
|
||||
if (tx_len + len > sizeof(tmp_buf))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(tmp_buf + tx_len, buf, len);
|
||||
tx_len += len;
|
||||
|
||||
|
|
|
|||
|
|
@ -463,6 +463,7 @@
|
|||
#define USB_DEVICE_ID_HP_X2 0x074d
|
||||
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
|
||||
#define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81
|
||||
#define I2C_DEVICE_ID_SURFACE_PRO_12IN 0x4376
|
||||
|
||||
#define USB_VENDOR_ID_ELECOM 0x056e
|
||||
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
|
||||
|
|
@ -683,6 +684,9 @@
|
|||
#define USB_DEVICE_ID_HARMONIX_WII_RB3_KEYBOARD 0x3330
|
||||
#define USB_DEVICE_ID_HARMONIX_WII_RB3_MPA_KEYBOARD_MODE 0x3338
|
||||
|
||||
#define USB_VENDOR_ID_HORI 0x0f0d
|
||||
#define USB_DEVICE_ID_HORI_WIRELESS_SWITCH_PAD 0x00f6
|
||||
|
||||
#define USB_VENDOR_ID_HP 0x03f0
|
||||
#define USB_PRODUCT_ID_HP_ELITE_PRESENTER_MOUSE_464A 0x464a
|
||||
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a
|
||||
|
|
@ -874,6 +878,7 @@
|
|||
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
|
||||
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
|
||||
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
|
||||
#define USB_DEVICE_ID_LENOVO_X13_TAB 0x62af
|
||||
#define USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161
|
||||
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
|
||||
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
|
||||
|
|
@ -1131,6 +1136,12 @@
|
|||
#define USB_VENDOR_ID_NVIDIA 0x0955
|
||||
#define USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER 0x7214
|
||||
|
||||
#define USB_VENDOR_ID_CRSC 0x1a2c
|
||||
#define USB_DEVICE_ID_ONEXPLAYER_GEN1 0xb001
|
||||
|
||||
#define USB_VENDOR_ID_WCH 0x1a86
|
||||
#define USB_DEVICE_ID_ONEXPLAYER_GEN2 0xfe00
|
||||
|
||||
#define USB_VENDOR_ID_ONTRAK 0x0a07
|
||||
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
|
||||
|
||||
|
|
@ -1406,6 +1417,11 @@
|
|||
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017 0x73f6
|
||||
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7
|
||||
|
||||
#define USB_VENDOR_ID_TELINK 0x248a
|
||||
#define USB_DEVICE_ID_TELINK_RAKK_DASIG_X 0xfb01
|
||||
#define USB_DEVICE_ID_TELINK_RAKK_DASIG_X_DONGLE 0xfa02
|
||||
#define USB_DEVICE_ID_TELINK_RAKK_DASIG_X_BT 0x8266
|
||||
|
||||
#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047
|
||||
#define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855
|
||||
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
|
|||
HID_BATTERY_QUIRK_AVOID_QUERY },
|
||||
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
|
||||
HID_BATTERY_QUIRK_AVOID_QUERY },
|
||||
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_PRO_12IN),
|
||||
HID_BATTERY_QUIRK_IGNORE },
|
||||
/*
|
||||
* Elan HID touchscreens seem to all report a non present battery,
|
||||
* set HID_BATTERY_QUIRK_IGNORE for all Elan I2C and USB HID devices.
|
||||
|
|
@ -519,6 +521,13 @@ static struct hid_battery *hidinput_find_battery(struct hid_device *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void hidinput_cleanup_battery(void *res)
|
||||
{
|
||||
struct hid_battery *bat = res;
|
||||
|
||||
list_del(&bat->list);
|
||||
}
|
||||
|
||||
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
||||
struct hid_field *field, bool is_percentage)
|
||||
{
|
||||
|
|
@ -610,6 +619,12 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
|||
|
||||
power_supply_powers(bat->ps, &dev->dev);
|
||||
list_add_tail(&bat->list, &dev->batteries);
|
||||
|
||||
error = devm_add_action_or_reset(&dev->dev,
|
||||
hidinput_cleanup_battery, bat);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_name:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
|
||||
static const __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
|
||||
const struct hid_device_id *id = hid_get_drvdata(hdev);
|
||||
unsigned long quirks = id->driver_data;
|
||||
|
||||
if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) {
|
||||
/* For Acer Aspire Switch 10 SW5-012 keyboard-dock */
|
||||
|
|
@ -44,7 +46,8 @@ static int ite_input_mapping(struct hid_device *hdev,
|
|||
int *max)
|
||||
{
|
||||
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
const struct hid_device_id *id = hid_get_drvdata(hdev);
|
||||
unsigned long quirks = id->driver_data;
|
||||
|
||||
if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) &&
|
||||
(usage->hid & HID_USAGE_PAGE) == 0x00880000) {
|
||||
|
|
@ -94,7 +97,7 @@ static int ite_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
{
|
||||
int ret;
|
||||
|
||||
hid_set_drvdata(hdev, (void *)id->driver_data);
|
||||
hid_set_drvdata(hdev, (void *)id);
|
||||
|
||||
ret = hid_open_report(hdev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -2405,6 +2405,15 @@ static int hid_go_cfg_probe(struct hid_device *hdev,
|
|||
|
||||
static void hid_go_cfg_remove(struct hid_device *hdev)
|
||||
{
|
||||
/*
|
||||
* cfg_setup is scheduled from hid_go_cfg_probe() with a 2 ms delay
|
||||
* and dereferences drvdata.hdev. Drain it here before tearing
|
||||
* down so the workqueue cannot run after hid_destroy_device()'s
|
||||
* put_device() has released the underlying hdev and dereference
|
||||
* a stale drvdata.hdev pointer.
|
||||
*/
|
||||
cancel_delayed_work_sync(&drvdata.go_cfg_setup);
|
||||
|
||||
guard(mutex)(&drvdata.cfg_mutex);
|
||||
sysfs_remove_groups(&hdev->dev.kobj, top_level_attr_groups);
|
||||
hid_hw_close(hdev);
|
||||
|
|
|
|||
|
|
@ -505,6 +505,7 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
|||
usage, bit, max);
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
|
|
@ -621,6 +622,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
|||
break;
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
|
|
@ -792,9 +794,10 @@ static int lenovo_raw_event(struct hid_device *hdev,
|
|||
* Lenovo TP X12 Tab KBD's Fn+XX is HID raw data defined. Report ID is 0x03
|
||||
* e.g.: Raw data received for MIC mute is 0x00020003.
|
||||
*/
|
||||
if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB
|
||||
|| hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2)
|
||||
&& size >= 4 && report->id == 0x03))
|
||||
if (unlikely((hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2 ||
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_X13_TAB) &&
|
||||
size >= 4 && report->id == 0x03))
|
||||
return lenovo_raw_event_TP_X12_tab(hdev, get_unaligned_le32(data));
|
||||
|
||||
return 0;
|
||||
|
|
@ -878,6 +881,7 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
|||
return lenovo_event_cptkbd(hdev, field, usage, value);
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
|
|
@ -1162,6 +1166,7 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
|||
break;
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
|
|
@ -1356,7 +1361,8 @@ static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
|
|||
*/
|
||||
|
||||
data->fn_lock = !(hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB ||
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2);
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_X12_TAB2 ||
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_X13_TAB);
|
||||
|
||||
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, data->fn_lock);
|
||||
|
||||
|
|
@ -1403,6 +1409,7 @@ static int lenovo_probe(struct hid_device *hdev,
|
|||
break;
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
|
|
@ -1491,6 +1498,7 @@ static void lenovo_remove(struct hid_device *hdev)
|
|||
break;
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
|
|
@ -1518,6 +1526,10 @@ static int lenovo_input_configured(struct hid_device *hdev,
|
|||
hi->input->propbit);
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X13_TAB:
|
||||
input_set_capability(hi->input, EV_KEY, KEY_PERFORMANCE);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1552,6 +1564,8 @@ static const struct hid_device_id lenovo_devices[] = {
|
|||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X13_TAB) },
|
||||
{ HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_YOGA_SLIM_7X_KEYBOARD) },
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ struct hidpp_battery {
|
|||
/**
|
||||
* struct hidpp_scroll_counter - Utility class for processing high-resolution
|
||||
* scroll events.
|
||||
* @dev: the input device for which events should be reported.
|
||||
* @wheel_multiplier: the scalar multiplier to be applied to each wheel event
|
||||
* @remainder: counts the number of high-resolution units moved since the last
|
||||
* low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
|
||||
|
|
@ -207,6 +206,9 @@ struct hidpp_device {
|
|||
|
||||
u8 wireless_feature_index;
|
||||
|
||||
int hires_wheel_multiplier;
|
||||
u8 hires_wheel_feature_index;
|
||||
|
||||
bool connected_once;
|
||||
};
|
||||
|
||||
|
|
@ -3710,6 +3712,7 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
|||
multiplier = 1;
|
||||
}
|
||||
|
||||
hidpp->hires_wheel_multiplier = multiplier;
|
||||
hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
|
||||
hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
|
||||
return 0;
|
||||
|
|
@ -3720,6 +3723,7 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
|
|||
int ret;
|
||||
unsigned long capabilities;
|
||||
|
||||
hidpp->hires_wheel_feature_index = 0xff;
|
||||
capabilities = hidpp->capabilities;
|
||||
|
||||
if (hidpp->protocol_major >= 2) {
|
||||
|
|
@ -3729,6 +3733,7 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
|
|||
&feature_index);
|
||||
if (!ret) {
|
||||
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL;
|
||||
hidpp->hires_wheel_feature_index = feature_index;
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scroll wheel\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3751,6 +3756,31 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
|
||||
u8 *data, int size)
|
||||
{
|
||||
if (hidpp->hires_wheel_feature_index == 0xff)
|
||||
return 0;
|
||||
|
||||
if (size < 5)
|
||||
return 0;
|
||||
|
||||
if (data[0] != REPORT_ID_HIDPP_LONG ||
|
||||
data[2] != hidpp->hires_wheel_feature_index)
|
||||
return 0;
|
||||
|
||||
if ((data[3] & 0xf0) == CMD_HIRES_WHEEL_SET_WHEEL_MODE) {
|
||||
u8 mode = data[4];
|
||||
bool hires = (mode & 0x02) != 0;
|
||||
int new_multiplier = (hires && hidpp->hires_wheel_multiplier > 0)
|
||||
? hidpp->hires_wheel_multiplier : 1;
|
||||
hidpp->vertical_wheel_counter.wheel_multiplier = new_multiplier;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Generic HID++ devices */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
@ -3947,6 +3977,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
|
||||
ret = hidpp20_hires_wheel_raw_event(hidpp, data, size);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4295,6 +4331,7 @@ static void hidpp_connect_event(struct work_struct *work)
|
|||
|
||||
ret = input_register_device(input);
|
||||
if (ret) {
|
||||
hidpp->input = NULL;
|
||||
input_free_device(input);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -443,11 +443,14 @@ static const struct mt_class mt_classes[] = {
|
|||
MT_QUIRK_CONTACT_CNT_ACCURATE,
|
||||
},
|
||||
{ .name = MT_CLS_YOGABOOK9I,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
||||
MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
MT_QUIRK_FORCE_MULTI_INPUT |
|
||||
MT_QUIRK_SEPARATE_APP_REPORT |
|
||||
MT_QUIRK_HOVERING |
|
||||
MT_QUIRK_YOGABOOK9I,
|
||||
.maxcontacts = 10,
|
||||
.export_all_inputs = true
|
||||
},
|
||||
{ .name = MT_CLS_EGALAX_P80H84,
|
||||
|
|
@ -1566,6 +1569,144 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Yoga Book 9 14IAH10 descriptor fixup.
|
||||
*
|
||||
* The device includes a HID_DG_TOUCHPAD application collection designed for
|
||||
* the Windows inbox HID driver's Win8 PTP touchpad mode. On Linux we want
|
||||
* only the HID_DG_TOUCHSCREEN collections. The touchpad collection (and the
|
||||
* HID_DG_BUTTONTYPE and Win8 compliance blob features it contains) must be
|
||||
* removed so hid-multitouch does not misclassify the touchscreen nodes as
|
||||
* indirect buttonpads.
|
||||
*
|
||||
* The firmware also resets if any USB control request is received while the
|
||||
* CDC-ACM interface is initialising (~1.18 s after enumeration). Dropping
|
||||
* the Win8 blob and Contact Count Max feature reports prevents the
|
||||
* GET_REPORT calls that hid-multitouch issues at probe.
|
||||
*/
|
||||
static void mt_yogabook9_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *size)
|
||||
{
|
||||
/* Usage Page (Digitizer), Usage (Touch Pad), Collection (Application) */
|
||||
static const __u8 tp_app_hdr[] = { 0x05, 0x0d, 0x09, 0x05, 0xa1, 0x01 };
|
||||
/* Vendor Usage Page 0xff00 (Win8 compliance blob header) */
|
||||
static const __u8 win8_page[] = { 0x06, 0x00, 0xff };
|
||||
/* Usage (Contact Count Max = 0x55) */
|
||||
static const __u8 ccmax_usage[] = { 0x09, 0x55 };
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Step 1: find and remove the Touch Pad application collection.
|
||||
* Walk HID short items from the collection header to its matching
|
||||
* End Collection, then close the gap with memmove.
|
||||
*/
|
||||
for (i = 0; i + sizeof(tp_app_hdr) <= *size; i++) {
|
||||
if (memcmp(rdesc + i, tp_app_hdr, sizeof(tp_app_hdr)) == 0) {
|
||||
__u8 *start = rdesc + i;
|
||||
__u8 *coll_end = NULL;
|
||||
__u8 *p = start;
|
||||
unsigned int drop;
|
||||
int depth = 0;
|
||||
|
||||
while (p < rdesc + *size) {
|
||||
__u8 b = *p;
|
||||
int ds = b & 3;
|
||||
int item_len;
|
||||
|
||||
if (b == 0xfe) { /* long item */
|
||||
if (p + 2 >= rdesc + *size)
|
||||
break;
|
||||
item_len = p[1] + 3;
|
||||
} else {
|
||||
item_len = (ds == 3) ? 5 : ds + 1;
|
||||
}
|
||||
if (p + item_len > rdesc + *size)
|
||||
break;
|
||||
|
||||
if ((b & 0xfc) == 0xa0)
|
||||
depth++; /* Collection */
|
||||
else if (b == 0xc0) {
|
||||
depth--; /* End Collection */
|
||||
if (depth == 0) {
|
||||
coll_end = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p += item_len;
|
||||
}
|
||||
|
||||
if (!coll_end) {
|
||||
hid_err(hdev,
|
||||
"Yoga Book 9: Touch Pad End Collection not found\n");
|
||||
break;
|
||||
}
|
||||
|
||||
drop = coll_end - start + 1;
|
||||
memmove(start, coll_end + 1, rdesc + *size - coll_end - 1);
|
||||
*size -= drop;
|
||||
hid_dbg(hdev,
|
||||
"Yoga Book 9: dropped Touch Pad collection (%u bytes)\n",
|
||||
drop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2: neutralize Win8 compliance blob feature reports remaining
|
||||
* in the touchscreen collections. Change Usage Page 0xff00 to 0x0f00
|
||||
* so the case 0xff0000c5 branch in mt_feature_mapping() is not reached
|
||||
* and no GET_REPORT is issued.
|
||||
*/
|
||||
for (i = 0; i + sizeof(win8_page) <= *size; i++) {
|
||||
if (memcmp(rdesc + i, win8_page, sizeof(win8_page)) == 0) {
|
||||
rdesc[i + 2] = 0x0f; /* 0xff00 -> 0x0f00 */
|
||||
hid_dbg(hdev,
|
||||
"Yoga Book 9: neutralized Win8 blob at offset %u\n",
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 3: neutralize Contact Count Max feature reports. Change usage
|
||||
* 0x55 (HID_DG_CONTACTMAX) to 0x00 so mt_feature_mapping() does not
|
||||
* issue GET_REPORT. The class maxcontacts field provides the value.
|
||||
*/
|
||||
for (i = 0; i + sizeof(ccmax_usage) <= *size; i++) {
|
||||
if (memcmp(rdesc + i, ccmax_usage, sizeof(ccmax_usage)) == 0) {
|
||||
rdesc[i + 1] = 0x00;
|
||||
hid_dbg(hdev,
|
||||
"Yoga Book 9: neutralized ContactMax at offset %u\n",
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 4: neutralize Surface Switch (0x57) and Button Switch (0x58)
|
||||
* feature report usages in the Device Configuration collection.
|
||||
* mt_set_modes() issues HID_REQ_SET_REPORT for these on every
|
||||
* input-device open/close; those repeated control requests hit the
|
||||
* firmware's CDC-ACM init window and trigger resets.
|
||||
*
|
||||
* Input Mode (0x52) is intentionally left intact. mt_set_modes()
|
||||
* sends it once at probe to set the device into touchscreen mode,
|
||||
* which flushes the firmware's contact buffer and clears a persistent
|
||||
* ghost contact (cid 2, fixed coordinates) that otherwise appears on
|
||||
* every enumeration. By probe time cdc_acm has already satisfied the
|
||||
* CDC-ACM init watchdog (~130 ms), so the single SET_REPORT for Input
|
||||
* Mode arrives safely after the reset window has closed.
|
||||
*/
|
||||
for (i = 0; i + 2 <= *size; i++) {
|
||||
if (rdesc[i] == 0x09 &&
|
||||
(rdesc[i + 1] == 0x57 ||
|
||||
rdesc[i + 1] == 0x58)) {
|
||||
hid_dbg(hdev,
|
||||
"Yoga Book 9: neutralized set-modes usage 0x%02x at offset %u\n",
|
||||
rdesc[i + 1], i);
|
||||
rdesc[i + 1] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *size)
|
||||
{
|
||||
|
|
@ -1595,6 +1736,10 @@ got: %x\n",
|
|||
}
|
||||
}
|
||||
|
||||
if (hdev->vendor == USB_VENDOR_ID_LENOVO &&
|
||||
hdev->product == USB_DEVICE_ID_LENOVO_YOGABOOK9I)
|
||||
mt_yogabook9_fixup(hdev, rdesc, size);
|
||||
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ enum joycon_ctlr_type {
|
|||
JOYCON_CTLR_TYPE_JCL = 0x01,
|
||||
JOYCON_CTLR_TYPE_JCR = 0x02,
|
||||
JOYCON_CTLR_TYPE_PRO = 0x03,
|
||||
JOYCON_CTLR_TYPE_LIC_PRO = 0x06,
|
||||
JOYCON_CTLR_TYPE_NESL = 0x09,
|
||||
JOYCON_CTLR_TYPE_NESR = 0x0A,
|
||||
JOYCON_CTLR_TYPE_SNES = 0x0B,
|
||||
|
|
@ -433,6 +434,25 @@ static const struct joycon_ctlr_button_mapping procon_button_mappings[] = {
|
|||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
/* Licensed Pro Controllers (e.g. HORI) swap X/Y bits in the report */
|
||||
static const struct joycon_ctlr_button_mapping lic_procon_button_mappings[] = {
|
||||
{ BTN_EAST, JC_BTN_A, },
|
||||
{ BTN_SOUTH, JC_BTN_B, },
|
||||
{ BTN_NORTH, JC_BTN_Y, },
|
||||
{ BTN_WEST, JC_BTN_X, },
|
||||
{ BTN_TL, JC_BTN_L, },
|
||||
{ BTN_TR, JC_BTN_R, },
|
||||
{ BTN_TL2, JC_BTN_ZL, },
|
||||
{ BTN_TR2, JC_BTN_ZR, },
|
||||
{ BTN_SELECT, JC_BTN_MINUS, },
|
||||
{ BTN_START, JC_BTN_PLUS, },
|
||||
{ BTN_THUMBL, JC_BTN_LSTICK, },
|
||||
{ BTN_THUMBR, JC_BTN_RSTICK, },
|
||||
{ BTN_MODE, JC_BTN_HOME, },
|
||||
{ BTN_Z, JC_BTN_CAP, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct joycon_ctlr_button_mapping nescon_button_mappings[] = {
|
||||
{ BTN_SOUTH, JC_BTN_A, },
|
||||
{ BTN_EAST, JC_BTN_B, },
|
||||
|
|
@ -695,7 +715,8 @@ static inline bool joycon_type_is_right_joycon(struct joycon_ctlr *ctlr)
|
|||
|
||||
static inline bool joycon_type_is_procon(struct joycon_ctlr *ctlr)
|
||||
{
|
||||
return ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO;
|
||||
return ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO ||
|
||||
ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO;
|
||||
}
|
||||
|
||||
static inline bool joycon_type_is_snescon(struct joycon_ctlr *ctlr)
|
||||
|
|
@ -1710,7 +1731,10 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
|
|||
joycon_report_left_stick(ctlr, rep);
|
||||
joycon_report_right_stick(ctlr, rep);
|
||||
joycon_report_dpad(ctlr, rep);
|
||||
joycon_report_buttons(ctlr, rep, procon_button_mappings);
|
||||
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO)
|
||||
joycon_report_buttons(ctlr, rep, lic_procon_button_mappings);
|
||||
else
|
||||
joycon_report_buttons(ctlr, rep, procon_button_mappings);
|
||||
} else if (joycon_type_is_any_nescon(ctlr)) {
|
||||
joycon_report_dpad(ctlr, rep);
|
||||
joycon_report_buttons(ctlr, rep, nescon_button_mappings);
|
||||
|
|
@ -2156,7 +2180,10 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
|
|||
joycon_config_left_stick(ctlr->input);
|
||||
joycon_config_right_stick(ctlr->input);
|
||||
joycon_config_dpad(ctlr->input);
|
||||
joycon_config_buttons(ctlr->input, procon_button_mappings);
|
||||
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO)
|
||||
joycon_config_buttons(ctlr->input, lic_procon_button_mappings);
|
||||
else
|
||||
joycon_config_buttons(ctlr->input, procon_button_mappings);
|
||||
} else if (joycon_type_is_any_nescon(ctlr)) {
|
||||
joycon_config_dpad(ctlr->input);
|
||||
joycon_config_buttons(ctlr->input, nescon_button_mappings);
|
||||
|
|
@ -2497,13 +2524,30 @@ static int joycon_init(struct hid_device *hdev)
|
|||
|
||||
if (joycon_has_joysticks(ctlr)) {
|
||||
/* get controller calibration data, and parse it */
|
||||
ret = joycon_request_calibration(ctlr);
|
||||
if (ret) {
|
||||
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO) {
|
||||
/*
|
||||
* We can function with default calibration, but it may be
|
||||
* inaccurate. Provide a warning, and continue on.
|
||||
* Licensed controllers may have incompatible SPI flash
|
||||
* layouts. Use default calibration values.
|
||||
*/
|
||||
hid_warn(hdev, "Analog stick positions may be inaccurate\n");
|
||||
hid_info(hdev, "using default cal for licensed controller\n");
|
||||
joycon_use_default_calibration(hdev,
|
||||
&ctlr->left_stick_cal_x,
|
||||
&ctlr->left_stick_cal_y,
|
||||
"left", 0);
|
||||
joycon_use_default_calibration(hdev,
|
||||
&ctlr->right_stick_cal_x,
|
||||
&ctlr->right_stick_cal_y,
|
||||
"right", 0);
|
||||
} else {
|
||||
ret = joycon_request_calibration(ctlr);
|
||||
if (ret) {
|
||||
/*
|
||||
* We can function with default calibration, but
|
||||
* it may be inaccurate. Provide a warning, and
|
||||
* continue on.
|
||||
*/
|
||||
hid_warn(hdev, "Analog stick positions may be inaccurate\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2521,8 +2565,13 @@ static int joycon_init(struct hid_device *hdev)
|
|||
/* Enable the IMU */
|
||||
ret = joycon_enable_imu(ctlr);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
|
||||
goto out_unlock;
|
||||
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO) {
|
||||
hid_dbg(hdev, "IMU enable failed for licensed controller, continuing\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2537,8 +2586,13 @@ static int joycon_init(struct hid_device *hdev)
|
|||
/* Enable rumble */
|
||||
ret = joycon_enable_rumble(ctlr);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
|
||||
goto out_unlock;
|
||||
if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_LIC_PRO) {
|
||||
hid_dbg(hdev, "rumble enable failed for licensed controller, continuing\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2807,6 +2861,8 @@ static const struct hid_device_id nintendo_hid_devices[] = {
|
|||
USB_DEVICE_ID_NINTENDO_GENCON) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_N64CON) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_HORI,
|
||||
USB_DEVICE_ID_HORI_WIRELESS_SWITCH_PAD) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, nintendo_hid_devices);
|
||||
|
|
|
|||
1580
drivers/hid/hid-oxp.c
Normal file
1580
drivers/hid/hid-oxp.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -112,6 +112,12 @@ struct ps_led_info {
|
|||
#define DS_BUTTONS2_TOUCHPAD BIT(1)
|
||||
#define DS_BUTTONS2_MIC_MUTE BIT(2)
|
||||
|
||||
/* DualSense Edge extra buttons in buttons[2], bits 4-7. */
|
||||
#define DS_EDGE_BUTTONS_FN1 BIT(4)
|
||||
#define DS_EDGE_BUTTONS_FN2 BIT(5)
|
||||
#define DS_EDGE_BUTTONS_LEFT_PADDLE BIT(6)
|
||||
#define DS_EDGE_BUTTONS_RIGHT_PADDLE BIT(7)
|
||||
|
||||
/* Status fields of DualSense input report. */
|
||||
#define DS_STATUS0_BATTERY_CAPACITY GENMASK(3, 0)
|
||||
#define DS_STATUS0_CHARGING GENMASK(7, 4)
|
||||
|
|
@ -178,6 +184,9 @@ struct dualsense {
|
|||
struct input_dev *touchpad;
|
||||
struct input_dev *jack;
|
||||
|
||||
/* True if this is a DualSense Edge (product 0x0df2). */
|
||||
bool is_edge;
|
||||
|
||||
/* Update version is used as a feature/capability version. */
|
||||
u16 update_version;
|
||||
|
||||
|
|
@ -1486,6 +1495,18 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
|
|||
input_report_key(ds->gamepad, BTN_THUMBL, ds_report->buttons[1] & DS_BUTTONS1_L3);
|
||||
input_report_key(ds->gamepad, BTN_THUMBR, ds_report->buttons[1] & DS_BUTTONS1_R3);
|
||||
input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME);
|
||||
|
||||
if (ds->is_edge) {
|
||||
input_report_key(ds->gamepad, BTN_TRIGGER_HAPPY1,
|
||||
ds_report->buttons[2] & DS_EDGE_BUTTONS_FN1);
|
||||
input_report_key(ds->gamepad, BTN_TRIGGER_HAPPY2,
|
||||
ds_report->buttons[2] & DS_EDGE_BUTTONS_FN2);
|
||||
input_report_key(ds->gamepad, BTN_TRIGGER_HAPPY3,
|
||||
ds_report->buttons[2] & DS_EDGE_BUTTONS_LEFT_PADDLE);
|
||||
input_report_key(ds->gamepad, BTN_TRIGGER_HAPPY4,
|
||||
ds_report->buttons[2] & DS_EDGE_BUTTONS_RIGHT_PADDLE);
|
||||
}
|
||||
|
||||
input_sync(ds->gamepad);
|
||||
|
||||
/*
|
||||
|
|
@ -1785,6 +1806,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
ds->use_vibration_v2 = ds->update_version >= DS_FEATURE_VERSION(2, 21);
|
||||
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
|
||||
ds->use_vibration_v2 = true;
|
||||
ds->is_edge = true;
|
||||
}
|
||||
|
||||
ret = ps_devices_list_add(ps_dev);
|
||||
|
|
@ -1802,6 +1824,15 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
|
|||
ret = PTR_ERR(ds->gamepad);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Register DualSense Edge back paddle and Fn buttons. */
|
||||
if (ds->is_edge) {
|
||||
input_set_capability(ds->gamepad, EV_KEY, BTN_TRIGGER_HAPPY1);
|
||||
input_set_capability(ds->gamepad, EV_KEY, BTN_TRIGGER_HAPPY2);
|
||||
input_set_capability(ds->gamepad, EV_KEY, BTN_TRIGGER_HAPPY3);
|
||||
input_set_capability(ds->gamepad, EV_KEY, BTN_TRIGGER_HAPPY4);
|
||||
}
|
||||
|
||||
/* Use gamepad input device name as primary device name for e.g. LEDs */
|
||||
ps_dev->input_dev_name = dev_name(&ds->gamepad->dev);
|
||||
|
||||
|
|
|
|||
75
drivers/hid/hid-rakk.c
Normal file
75
drivers/hid/hid-rakk.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* HID driver for Rakk devices
|
||||
*
|
||||
* Copyright (c) 2026 Karl Cayme
|
||||
*
|
||||
* The Rakk Dasig X gaming mouse has a faulty HID report descriptor that
|
||||
* declares USAGE_MAXIMUM = 3 (buttons 1-3) while actually sending 5 button
|
||||
* bits (REPORT_COUNT = 5). This causes the kernel to ignore side buttons
|
||||
* (buttons 4 and 5). This driver fixes the descriptor so all 5 buttons
|
||||
* are properly recognized across 3 modes (wired, dongle, and Bluetooth).
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
/*
|
||||
* The faulty byte is at offset 17 in the report descriptor for all three
|
||||
* connection modes (USB direct, wireless dongle, and Bluetooth).
|
||||
*
|
||||
* Bytes 16-17 are: 0x29 0x03 (USAGE_MAXIMUM = 3)
|
||||
* The fix changes byte 17 to 0x05 (USAGE_MAXIMUM = 5).
|
||||
*
|
||||
* Original descriptor bytes 0-17:
|
||||
* 05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 19 01 29 03
|
||||
* ^^
|
||||
* Should be 0x05 to declare 5 buttons instead of 3.
|
||||
*/
|
||||
#define RAKK_RDESC_USAGE_MAX_OFFSET 17
|
||||
#define RAKK_RDESC_USAGE_MAX_ORIG 0x03
|
||||
#define RAKK_RDESC_USAGE_MAX_FIXED 0x05
|
||||
#define RAKK_RDESC_USB_SIZE 193
|
||||
#define RAKK_RDESC_DONGLE_SIZE 150
|
||||
#define RAKK_RDESC_BT_SIZE 89
|
||||
|
||||
static const __u8 *rakk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (((*rsize == RAKK_RDESC_USB_SIZE &&
|
||||
hdev->product == USB_DEVICE_ID_TELINK_RAKK_DASIG_X) ||
|
||||
(*rsize == RAKK_RDESC_DONGLE_SIZE &&
|
||||
hdev->product == USB_DEVICE_ID_TELINK_RAKK_DASIG_X_DONGLE) ||
|
||||
(*rsize == RAKK_RDESC_BT_SIZE &&
|
||||
hdev->product == USB_DEVICE_ID_TELINK_RAKK_DASIG_X_BT)) &&
|
||||
rdesc[RAKK_RDESC_USAGE_MAX_OFFSET] == RAKK_RDESC_USAGE_MAX_ORIG) {
|
||||
hid_info(hdev, "fixing Rakk Dasig X button count (3 -> 5)\n");
|
||||
rdesc[RAKK_RDESC_USAGE_MAX_OFFSET] = RAKK_RDESC_USAGE_MAX_FIXED;
|
||||
}
|
||||
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id rakk_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TELINK,
|
||||
USB_DEVICE_ID_TELINK_RAKK_DASIG_X) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TELINK,
|
||||
USB_DEVICE_ID_TELINK_RAKK_DASIG_X_DONGLE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TELINK,
|
||||
USB_DEVICE_ID_TELINK_RAKK_DASIG_X_BT) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, rakk_devices);
|
||||
|
||||
static struct hid_driver rakk_driver = {
|
||||
.name = "rakk",
|
||||
.id_table = rakk_devices,
|
||||
.report_fixup = rakk_report_fixup,
|
||||
};
|
||||
module_hid_driver(rakk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("HID driver for Rakk Dasig X mouse - fix side button support");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Karl Cayme");
|
||||
|
|
@ -1852,18 +1852,8 @@ static int sony_play_effect(struct input_dev *dev, void *data,
|
|||
|
||||
static int sony_init_ff(struct sony_sc *sc)
|
||||
{
|
||||
struct hid_input *hidinput;
|
||||
struct input_dev *input_dev;
|
||||
|
||||
if (list_empty(&sc->hdev->inputs)) {
|
||||
hid_err(sc->hdev, "no inputs found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list);
|
||||
input_dev = hidinput->input;
|
||||
|
||||
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
|
||||
return input_ff_create_memless(input_dev, NULL, sony_play_effect);
|
||||
input_set_capability(sc->input_dev, EV_FF, FF_RUMBLE);
|
||||
return input_ff_create_memless(sc->input_dev, NULL, sony_play_effect);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -2150,6 +2140,8 @@ static int sony_input_configured(struct hid_device *hdev,
|
|||
int append_dev_id;
|
||||
int ret;
|
||||
|
||||
sc->input_dev = hidinput->input;
|
||||
|
||||
ret = sony_set_device_id(sc);
|
||||
if (ret < 0) {
|
||||
hid_err(hdev, "failed to allocate the device id\n");
|
||||
|
|
@ -2310,7 +2302,6 @@ static int sony_input_configured(struct hid_device *hdev,
|
|||
goto err_close;
|
||||
}
|
||||
|
||||
sc->input_dev = hidinput->input;
|
||||
return 0;
|
||||
err_close:
|
||||
hid_hw_close(hdev);
|
||||
|
|
|
|||
|
|
@ -2403,7 +2403,7 @@ static const struct wiimod_ops wiimod_guitar = {
|
|||
.in_ext = wiimod_guitar_in_ext,
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
* Turntable
|
||||
* DJ Hero came with a Turntable Controller that was plugged in
|
||||
* as an extension.
|
||||
|
|
@ -2439,15 +2439,15 @@ static const __u16 wiimod_turntable_map[] = {
|
|||
static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
||||
{
|
||||
__u8 be, cs, sx, sy, ed, rtt, rbg, rbr, rbb, ltt, lbg, lbr, lbb, bp, bm;
|
||||
/*
|
||||
/*
|
||||
* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 0 | RTT<4:3> | SX <5:0> |
|
||||
* 1 | RTT<2:1> | SY <5:0> |
|
||||
* 0 | RTT<4:3> | SX <5:0> |
|
||||
* 1 | RTT<2:1> | SY <5:0> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 2 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 3 | ED<2:0> | LTT<4:0> |
|
||||
* 3 | ED<2:0> | LTT<4:0> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 4 | 0 | 0 | LBR | B- | 0 | B+ | RBR | LTT<5> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
|
|
@ -2458,20 +2458,20 @@ static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
|||
* With Motion+ enabled, it will look like this:
|
||||
* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 1 | RTT<4:3> | SX <5:1> | 0 |
|
||||
* 2 | RTT<2:1> | SY <5:1> | 0 |
|
||||
* 1 | RTT<4:3> | SX <5:1> | 0 |
|
||||
* 2 | RTT<2:1> | SY <5:1> | 0 |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 3 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 4 | ED<2:0> | LTT<4:0> |
|
||||
* 4 | ED<2:0> | LTT<4:0> |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 5 | 0 | 0 | LBR | B- | 0 | B+ | RBR | XXXX |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
* 6 | LBB | 0 | RBG | BE | LBG | RBB | XXXX | XXXX |
|
||||
*------+------+-----+-----+-----+-----+------+------+--------+
|
||||
*/
|
||||
|
||||
be = !(ext[5] & 0x10);
|
||||
|
||||
be = !(ext[5] & 0x10);
|
||||
cs = ((ext[2] & 0x1e));
|
||||
sx = ext[0] & 0x3f;
|
||||
sy = ext[1] & 0x3f;
|
||||
|
|
@ -2499,32 +2499,32 @@ static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
|
|||
input_report_abs(wdata->extension.input, ABS_HAT1X, ltt);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT2X, cs);
|
||||
input_report_abs(wdata->extension.input, ABS_HAT3X, ed);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_RIGHT],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_RIGHT],
|
||||
rbg);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_RIGHT],
|
||||
rbr);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_RIGHT],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_RIGHT],
|
||||
rbb);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_LEFT],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_LEFT],
|
||||
lbg);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_LEFT],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_LEFT],
|
||||
lbr);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_LEFT],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_LEFT],
|
||||
lbb);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_EUPHORIA],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_EUPHORIA],
|
||||
be);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_PLUS],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_PLUS],
|
||||
bp);
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_MINUS],
|
||||
input_report_key(wdata->extension.input,
|
||||
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_MINUS],
|
||||
bm);
|
||||
|
||||
input_sync(wdata->extension.input);
|
||||
|
|
@ -2557,7 +2557,7 @@ static void wiimod_turntable_close(struct input_dev *dev)
|
|||
static int wiimod_turntable_probe(const struct wiimod_ops *ops,
|
||||
struct wiimote_data *wdata)
|
||||
{
|
||||
int ret, i;
|
||||
int ret, i;
|
||||
|
||||
wdata->extension.input = input_allocate_device();
|
||||
if (!wdata->extension.input)
|
||||
|
|
@ -2594,9 +2594,9 @@ static int wiimod_turntable_probe(const struct wiimod_ops *ops,
|
|||
input_set_abs_params(wdata->extension.input,
|
||||
ABS_HAT1X, -8, 8, 0, 0);
|
||||
input_set_abs_params(wdata->extension.input,
|
||||
ABS_HAT2X, 0, 31, 1, 1);
|
||||
ABS_HAT2X, 0, 31, 1, 1);
|
||||
input_set_abs_params(wdata->extension.input,
|
||||
ABS_HAT3X, 0, 7, 0, 0);
|
||||
ABS_HAT3X, 0, 7, 0, 0);
|
||||
ret = input_register_device(wdata->extension.input);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
|
|||
#endif
|
||||
|
||||
static const struct i2c_device_id i2c_hid_of_id_table[] = {
|
||||
{ "hid" },
|
||||
{ "hid-over-i2c" },
|
||||
{ .name = "hid" },
|
||||
{ .name = "hid-over-i2c" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_hid_of_id_table);
|
||||
|
|
|
|||
|
|
@ -784,20 +784,72 @@ static int quickspi_resume(struct device *device)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* A wake-enabled device keeps its power and state across suspend, so
|
||||
* only restore the THC context. Resetting it here would discard a
|
||||
* pending wake touch event and break wake-on-touch.
|
||||
*/
|
||||
if (device_may_wakeup(qsdev->dev)) {
|
||||
thc_interrupt_config(qsdev->thc_hw);
|
||||
|
||||
thc_interrupt_enable(qsdev->thc_hw, true);
|
||||
|
||||
ret = thc_dma_configure(qsdev->thc_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return thc_interrupt_quiesce(qsdev->thc_hw, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise the touch IC may have lost power across suspend. On
|
||||
* platforms that suspend through s2idle (for example the Surface Pro
|
||||
* 10, whose firmware exposes s2idle as the only mem_sleep state) the
|
||||
* IC loses power the same way it does across hibernation. A plain
|
||||
* HIDSPI_ON is then not acknowledged and the descriptor read fails, so
|
||||
* re-enumerate the device through the full reset flow already used by
|
||||
* quickspi_restore().
|
||||
*/
|
||||
thc_spi_input_output_address_config(qsdev->thc_hw,
|
||||
qsdev->input_report_hdr_addr,
|
||||
qsdev->input_report_bdy_addr,
|
||||
qsdev->output_report_addr);
|
||||
|
||||
ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val,
|
||||
qsdev->spi_read_io_mode,
|
||||
qsdev->spi_read_opcode,
|
||||
qsdev->spi_packet_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val,
|
||||
qsdev->spi_write_io_mode,
|
||||
qsdev->spi_write_opcode,
|
||||
qsdev->spi_packet_size,
|
||||
qsdev->performance_limit);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
thc_interrupt_config(qsdev->thc_hw);
|
||||
|
||||
thc_interrupt_enable(qsdev->thc_hw, true);
|
||||
|
||||
/* The touch IC may have lost power, reset it to recover */
|
||||
ret = reset_tic(qsdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = thc_dma_configure(qsdev->thc_hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = thc_interrupt_quiesce(qsdev->thc_hw, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
thc_ltr_config(qsdev->thc_hw,
|
||||
qsdev->active_ltr_val,
|
||||
qsdev->low_power_ltr_val);
|
||||
|
||||
if (!device_may_wakeup(qsdev->dev))
|
||||
return quickspi_set_power(qsdev, HIDSPI_ON);
|
||||
thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE);
|
||||
|
||||
qsdev->state = QUICKSPI_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,8 +595,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
|
|||
if (!READ_ONCE(uhid->running))
|
||||
return -EINVAL;
|
||||
|
||||
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
|
||||
min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
|
||||
hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, UHID_DATA_MAX,
|
||||
min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -606,8 +606,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
|
|||
if (!READ_ONCE(uhid->running))
|
||||
return -EINVAL;
|
||||
|
||||
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
|
||||
min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
|
||||
hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, UHID_DATA_MAX,
|
||||
min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_buf.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
|
@ -1367,6 +1368,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
struct usb_endpoint_descriptor *ep;
|
||||
struct usbhid_device *usbhid;
|
||||
struct hid_device *hid;
|
||||
struct seq_buf hid_name;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1398,7 +1400,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
||||
hid->product = le16_to_cpu(dev->descriptor.idProduct);
|
||||
hid->version = le16_to_cpu(dev->descriptor.bcdDevice);
|
||||
hid->name[0] = 0;
|
||||
seq_buf_init(&hid_name, hid->name, sizeof(hid->name));
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol ==
|
||||
USB_INTERFACE_PROTOCOL_MOUSE)
|
||||
hid->type = HID_TYPE_USBMOUSE;
|
||||
|
|
@ -1406,22 +1408,23 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
hid->type = HID_TYPE_USBNONE;
|
||||
|
||||
if (dev->manufacturer)
|
||||
strscpy(hid->name, dev->manufacturer, sizeof(hid->name));
|
||||
seq_buf_puts(&hid_name, dev->manufacturer);
|
||||
|
||||
if (dev->product) {
|
||||
if (dev->manufacturer)
|
||||
strlcat(hid->name, " ", sizeof(hid->name));
|
||||
strlcat(hid->name, dev->product, sizeof(hid->name));
|
||||
seq_buf_puts(&hid_name, " ");
|
||||
seq_buf_puts(&hid_name, dev->product);
|
||||
}
|
||||
|
||||
if (!strlen(hid->name))
|
||||
if (!seq_buf_used(&hid_name))
|
||||
snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
usb_make_path(dev, hid->phys, sizeof(hid->phys));
|
||||
strlcat(hid->phys, "/input", sizeof(hid->phys));
|
||||
len = strlen(hid->phys);
|
||||
len = strnlen(hid->phys, sizeof(hid->phys));
|
||||
strscpy(hid->phys + len, "/input", sizeof(hid->phys) - len);
|
||||
len = strnlen(hid->phys, sizeof(hid->phys));
|
||||
if (len < sizeof(hid->phys) - 1)
|
||||
snprintf(hid->phys + len, sizeof(hid->phys) - len,
|
||||
"%d", intf->altsetting[0].desc.bInterfaceNumber);
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
|
|||
pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
|
||||
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
|
||||
pidff->set_effect_type->value[0] =
|
||||
pidff->create_new_effect_type->value[0];
|
||||
pidff_get_effect_type_id(pidff, effect);
|
||||
|
||||
pidff_set_duration(&pidff->set_effect[PID_DURATION],
|
||||
effect->replay.length);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/usb/input.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/seq_buf.h>
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
|
|
@ -266,8 +267,10 @@ static int usb_kbd_probe(struct usb_interface *iface,
|
|||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct usb_kbd *kbd;
|
||||
struct input_dev *input_dev;
|
||||
struct seq_buf kbd_name;
|
||||
int i, pipe, maxp;
|
||||
int error = -ENOMEM;
|
||||
size_t len;
|
||||
|
||||
interface = iface->cur_altsetting;
|
||||
|
||||
|
|
@ -292,24 +295,26 @@ static int usb_kbd_probe(struct usb_interface *iface,
|
|||
kbd->usbdev = dev;
|
||||
kbd->dev = input_dev;
|
||||
spin_lock_init(&kbd->leds_lock);
|
||||
seq_buf_init(&kbd_name, kbd->name, sizeof(kbd->name));
|
||||
|
||||
if (dev->manufacturer)
|
||||
strscpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
|
||||
seq_buf_puts(&kbd_name, dev->manufacturer);
|
||||
|
||||
if (dev->product) {
|
||||
if (dev->manufacturer)
|
||||
strlcat(kbd->name, " ", sizeof(kbd->name));
|
||||
strlcat(kbd->name, dev->product, sizeof(kbd->name));
|
||||
seq_buf_puts(&kbd_name, " ");
|
||||
seq_buf_puts(&kbd_name, dev->product);
|
||||
}
|
||||
|
||||
if (!strlen(kbd->name))
|
||||
if (!seq_buf_used(&kbd_name))
|
||||
snprintf(kbd->name, sizeof(kbd->name),
|
||||
"USB HIDBP Keyboard %04x:%04x",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
|
||||
strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
|
||||
len = strnlen(kbd->phys, sizeof(kbd->phys));
|
||||
strscpy(kbd->phys + len, "/input0", sizeof(kbd->phys) - len);
|
||||
|
||||
input_dev->name = kbd->name;
|
||||
input_dev->phys = kbd->phys;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/usb/input.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/seq_buf.h>
|
||||
|
||||
/* for apple IDs */
|
||||
#ifdef CONFIG_USB_HID_MODULE
|
||||
|
|
@ -110,8 +111,10 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
|
|||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct usb_mouse *mouse;
|
||||
struct input_dev *input_dev;
|
||||
struct seq_buf mouse_name;
|
||||
int pipe, maxp;
|
||||
int error = -ENOMEM;
|
||||
size_t len;
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
|
||||
|
|
@ -140,24 +143,26 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
|
|||
|
||||
mouse->usbdev = dev;
|
||||
mouse->dev = input_dev;
|
||||
seq_buf_init(&mouse_name, mouse->name, sizeof(mouse->name));
|
||||
|
||||
if (dev->manufacturer)
|
||||
strscpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
|
||||
seq_buf_puts(&mouse_name, dev->manufacturer);
|
||||
|
||||
if (dev->product) {
|
||||
if (dev->manufacturer)
|
||||
strlcat(mouse->name, " ", sizeof(mouse->name));
|
||||
strlcat(mouse->name, dev->product, sizeof(mouse->name));
|
||||
seq_buf_puts(&mouse_name, " ");
|
||||
seq_buf_puts(&mouse_name, dev->product);
|
||||
}
|
||||
|
||||
if (!strlen(mouse->name))
|
||||
if (!seq_buf_used(&mouse_name))
|
||||
snprintf(mouse->name, sizeof(mouse->name),
|
||||
"USB HIDBP Mouse %04x:%04x",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
|
||||
strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
|
||||
len = strnlen(mouse->phys, sizeof(mouse->phys));
|
||||
strscpy(mouse->phys + len, "/input0", sizeof(mouse->phys) - len);
|
||||
|
||||
input_dev->name = mouse->name;
|
||||
input_dev->phys = mouse->phys;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ static void wacom_wac_queue_insert(struct hid_device *hdev,
|
|||
{
|
||||
bool warned = false;
|
||||
|
||||
while (kfifo_avail(fifo) < size) {
|
||||
while (kfifo_avail(fifo) < size && !kfifo_is_empty(fifo)) {
|
||||
if (!warned)
|
||||
hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__);
|
||||
warned = true;
|
||||
|
|
@ -62,7 +62,9 @@ static void wacom_wac_queue_insert(struct hid_device *hdev,
|
|||
kfifo_skip(fifo);
|
||||
}
|
||||
|
||||
kfifo_in(fifo, raw_data, size);
|
||||
if (!kfifo_in(fifo, raw_data, size))
|
||||
hid_warn_ratelimited(hdev, "%s: report is too large (%d)\n",
|
||||
__func__, size);
|
||||
}
|
||||
|
||||
static void wacom_wac_queue_flush(struct hid_device *hdev,
|
||||
|
|
@ -70,11 +72,10 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
|
|||
{
|
||||
while (!kfifo_is_empty(fifo)) {
|
||||
int size = kfifo_peek_len(fifo);
|
||||
u8 *buf;
|
||||
u8 *buf __free(kfree) = kzalloc(size, GFP_ATOMIC);
|
||||
unsigned int count;
|
||||
int err;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
kfifo_skip(fifo);
|
||||
continue;
|
||||
|
|
@ -87,7 +88,6 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
|
|||
// to flush seems reasonable enough, however.
|
||||
hid_warn(hdev, "%s: removed fifo entry with unexpected size\n",
|
||||
__func__);
|
||||
kfree(buf);
|
||||
continue;
|
||||
}
|
||||
err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, size, false);
|
||||
|
|
@ -95,8 +95,6 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
|
|||
hid_warn(hdev, "%s: unable to flush event due to error %d\n",
|
||||
__func__, err);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2462,16 +2460,16 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
|
|||
|
||||
error = wacom_register_inputs(wacom);
|
||||
if (error)
|
||||
goto fail;
|
||||
goto fail_hw_stop;
|
||||
|
||||
if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) {
|
||||
error = wacom_initialize_leds(wacom);
|
||||
if (error)
|
||||
goto fail;
|
||||
goto fail_hw_stop;
|
||||
|
||||
error = wacom_initialize_remotes(wacom);
|
||||
if (error)
|
||||
goto fail;
|
||||
goto fail_hw_stop;
|
||||
}
|
||||
|
||||
if (!wireless) {
|
||||
|
|
@ -2485,14 +2483,14 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
|
|||
cancel_delayed_work_sync(&wacom->init_work);
|
||||
_wacom_query_tablet_data(wacom);
|
||||
error = -ENODEV;
|
||||
goto fail_quirks;
|
||||
goto fail_hw_stop;
|
||||
}
|
||||
|
||||
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) {
|
||||
error = hid_hw_open(hdev);
|
||||
if (error) {
|
||||
hid_err(hdev, "hw open failed\n");
|
||||
goto fail_quirks;
|
||||
goto fail_hw_stop;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2501,7 +2499,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
|
|||
|
||||
return 0;
|
||||
|
||||
fail_quirks:
|
||||
fail_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
fail:
|
||||
wacom_release_resources(wacom);
|
||||
|
|
|
|||
|
|
@ -105,13 +105,6 @@ $(MAKE_DIRS):
|
|||
$(call msg,MKDIR,,$@)
|
||||
$(Q)mkdir -p $@
|
||||
|
||||
# LLVM's ld.lld doesn't support all the architectures, so use it only on x86
|
||||
ifeq ($(SRCARCH),x86)
|
||||
LLD := lld
|
||||
else
|
||||
LLD := ld
|
||||
endif
|
||||
|
||||
DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
|
||||
|
||||
TEST_GEN_PROGS_EXTENDED += $(DEFAULT_BPFTOOL)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user