summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.c9
-rw-r--r--drivers/hid/hid-apple.c20
-rw-r--r--drivers/hid/hid-asus.c115
-rw-r--r--drivers/hid/hid-core.c93
-rw-r--r--drivers/hid/hid-hyperv.c4
-rw-r--r--drivers/hid/hid-ids.h13
-rw-r--r--drivers/hid/hid-input-test.c10
-rw-r--r--drivers/hid/hid-input.c51
-rw-r--r--drivers/hid/hid-lenovo.c19
-rw-r--r--drivers/hid/hid-logitech-dj.c4
-rw-r--r--drivers/hid/hid-logitech-hidpp.c8
-rw-r--r--drivers/hid/hid-magicmouse.c56
-rw-r--r--drivers/hid/hid-multitouch.c16
-rw-r--r--drivers/hid/hid-nintendo.c38
-rw-r--r--drivers/hid/hid-ntrig.c3
-rw-r--r--drivers/hid/hid-quirks.c7
-rw-r--r--drivers/hid/hid-thrustmaster.c1
-rw-r--r--drivers/hid/hid-uclogic-core.c7
-rw-r--r--drivers/hid/usbhid/hid-core.c25
-rw-r--r--drivers/hid/usbhid/usbkbd.c2
-rw-r--r--drivers/hid/wacom_sys.c7
-rw-r--r--drivers/hid/wacom_wac.c1
22 files changed, 374 insertions, 135 deletions
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index 8420c227e21b..bd3cc5636648 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -38,6 +38,9 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
struct hid_bpf_ops *e;
int ret;
+ if (unlikely(hdev->bpf.destroyed))
+ return ERR_PTR(-ENODEV);
+
if (type >= HID_REPORT_TYPES)
return ERR_PTR(-EINVAL);
@@ -93,6 +96,9 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
struct hid_bpf_ops *e;
int ret, idx;
+ if (unlikely(hdev->bpf.destroyed))
+ return -ENODEV;
+
if (rtype >= HID_REPORT_TYPES)
return -EINVAL;
@@ -130,6 +136,9 @@ int dispatch_hid_bpf_output_report(struct hid_device *hdev,
struct hid_bpf_ops *e;
int ret, idx;
+ if (unlikely(hdev->bpf.destroyed))
+ return -ENODEV;
+
idx = srcu_read_lock(&hdev->bpf.srcu);
list_for_each_entry_srcu(e, &hdev->bpf.prog_list, list,
srcu_read_lock_held(&hdev->bpf.srcu)) {
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index d900dd05c335..25d1edb6a210 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -890,7 +890,8 @@ static int apple_magic_backlight_init(struct hid_device *hdev)
backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS];
backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER];
- if (!backlight->brightness || !backlight->power)
+ if (!backlight->brightness || backlight->brightness->maxfield < 2 ||
+ !backlight->power || backlight->power->maxfield < 2)
return -ENODEV;
backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
@@ -933,10 +934,12 @@ static int apple_probe(struct hid_device *hdev,
return ret;
}
- timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
- mod_timer(&asc->battery_timer,
- jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
- apple_fetch_battery(hdev);
+ if (quirks & APPLE_RDESC_BATTERY) {
+ timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
+ mod_timer(&asc->battery_timer,
+ jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
+ apple_fetch_battery(hdev);
+ }
if (quirks & APPLE_BACKLIGHT_CTL)
apple_backlight_init(hdev);
@@ -950,7 +953,9 @@ static int apple_probe(struct hid_device *hdev,
return 0;
out_err:
- del_timer_sync(&asc->battery_timer);
+ if (quirks & APPLE_RDESC_BATTERY)
+ del_timer_sync(&asc->battery_timer);
+
hid_hw_stop(hdev);
return ret;
}
@@ -959,7 +964,8 @@ static void apple_remove(struct hid_device *hdev)
{
struct apple_sc *asc = hid_get_drvdata(hdev);
- del_timer_sync(&asc->battery_timer);
+ if (asc->quirks & APPLE_RDESC_BATTERY)
+ del_timer_sync(&asc->battery_timer);
hid_hw_stop(hdev);
}
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index bcdd168cdc6d..6b90d2c03e88 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define FEATURE_KBD_LED_REPORT_ID1 0x5d
#define FEATURE_KBD_LED_REPORT_ID2 0x5e
+#define ROG_ALLY_REPORT_SIZE 64
+#define ROG_ALLY_X_MIN_MCU 313
+#define ROG_ALLY_MIN_MCU 319
+
#define SUPPORT_KBD_BACKLIGHT BIT(0)
#define MAX_TOUCH_MAJOR 8
@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define QUIRK_MEDION_E1239T BIT(10)
#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
+#define QUIRK_ROG_ALLY_XPAD BIT(13)
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
QUIRK_NO_INIT_REPORTS | \
@@ -534,9 +539,99 @@ static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
}
+/*
+ * We don't care about any other part of the string except the version section.
+ * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01
+ * The bytes "5a 05 03 31 00 1a 13" and possibly more come before the version
+ * string, and there may be additional bytes after the version string such as
+ * "75 00 74 00 65 00" or a postfix such as "_T01"
+ */
+static int mcu_parse_version_string(const u8 *response, size_t response_size)
+{
+ const u8 *end = response + response_size;
+ const u8 *p = response;
+ int dots, err, version;
+ char buf[4];
+
+ dots = 0;
+ while (p < end && dots < 2) {
+ if (*p++ == '.')
+ dots++;
+ }
+
+ if (dots != 2 || p >= end || (p + 3) >= end)
+ return -EINVAL;
+
+ memcpy(buf, p, 3);
+ buf[3] = '\0';
+
+ err = kstrtoint(buf, 10, &version);
+ if (err || version < 0)
+ return -EINVAL;
+
+ return version;
+}
+
+static int mcu_request_version(struct hid_device *hdev)
+{
+ u8 *response __free(kfree) = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
+ const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 };
+ int ret;
+
+ if (!response)
+ return -ENOMEM;
+
+ ret = asus_kbd_set_report(hdev, request, sizeof(request));
+ if (ret < 0)
+ return ret;
+
+ ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response,
+ ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT,
+ HID_REQ_GET_REPORT);
+ if (ret < 0)
+ return ret;
+
+ ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE);
+ if (ret < 0) {
+ pr_err("Failed to parse MCU version: %d\n", ret);
+ print_hex_dump(KERN_ERR, "MCU: ", DUMP_PREFIX_NONE,
+ 16, 1, response, ROG_ALLY_REPORT_SIZE, false);
+ }
+
+ return ret;
+}
+
+static void validate_mcu_fw_version(struct hid_device *hdev, int idProduct)
+{
+ int min_version, version;
+
+ version = mcu_request_version(hdev);
+ if (version < 0)
+ return;
+
+ switch (idProduct) {
+ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY:
+ min_version = ROG_ALLY_MIN_MCU;
+ break;
+ case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X:
+ min_version = ROG_ALLY_X_MIN_MCU;
+ break;
+ default:
+ min_version = 0;
+ }
+
+ if (version < min_version) {
+ hid_warn(hdev,
+ "The MCU firmware version must be %d or greater to avoid issues with suspend.\n",
+ min_version);
+ }
+}
+
static int asus_kbd_register_leds(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct usb_interface *intf;
+ struct usb_device *udev;
unsigned char kbd_func;
int ret;
@@ -560,6 +655,14 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
if (ret < 0)
return ret;
}
+
+ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) {
+ intf = to_usb_interface(hdev->dev.parent);
+ udev = interface_to_usbdev(intf);
+ validate_mcu_fw_version(hdev,
+ le16_to_cpu(udev->descriptor.idProduct));
+ }
+
} else {
/* Initialize keyboard */
ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID);
@@ -1107,7 +1210,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
- if (!drvdata->input) {
+ /*
+ * Check that input registration succeeded. Checking that
+ * HID_CLAIMED_INPUT is set prevents a UAF when all input devices
+ * were freed during registration due to no usages being mapped,
+ * leaving drvdata->input pointing to freed memory.
+ */
+ if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) {
hid_err(hdev, "Asus input not registered\n");
ret = -ENOMEM;
goto err_stop_hw;
@@ -1280,10 +1389,10 @@ static const struct hid_device_id asus_devices[] = {
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD},
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 155deef867ac..9910c6d3fef3 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -46,6 +46,38 @@ module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600
MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver");
/*
+ * Convert a signed n-bit integer to signed 32-bit integer.
+ */
+
+static s32 snto32(__u32 value, unsigned int n)
+{
+ if (!value || !n)
+ return 0;
+
+ if (n > 32)
+ n = 32;
+
+ return sign_extend32(value, n - 1);
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+static u32 s32ton(__s32 value, unsigned int n)
+{
+ s32 a;
+
+ if (!value || !n)
+ return 0;
+
+ a = value >> (n - 1);
+ if (a && a != -1)
+ return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+ return value & ((1 << n) - 1);
+}
+
+/*
* Register a new report for a device.
*/
@@ -425,7 +457,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
* both this and the standard encoding. */
raw_value = item_sdata(item);
if (!(raw_value & 0xfffffff0))
- parser->global.unit_exponent = hid_snto32(raw_value, 4);
+ parser->global.unit_exponent = snto32(raw_value, 4);
else
parser->global.unit_exponent = raw_value;
return 0;
@@ -1318,46 +1350,6 @@ alloc_err:
EXPORT_SYMBOL_GPL(hid_open_report);
/*
- * Convert a signed n-bit integer to signed 32-bit integer. Common
- * cases are done through the compiler, the screwed things has to be
- * done by hand.
- */
-
-static s32 snto32(__u32 value, unsigned n)
-{
- if (!value || !n)
- return 0;
-
- if (n > 32)
- n = 32;
-
- switch (n) {
- case 8: return ((__s8)value);
- case 16: return ((__s16)value);
- case 32: return ((__s32)value);
- }
- return value & (1 << (n - 1)) ? value | (~0U << n) : value;
-}
-
-s32 hid_snto32(__u32 value, unsigned n)
-{
- return snto32(value, n);
-}
-EXPORT_SYMBOL_GPL(hid_snto32);
-
-/*
- * Convert a signed 32-bit integer to a signed n-bit integer.
- */
-
-static u32 s32ton(__s32 value, unsigned n)
-{
- s32 a = value >> (n - 1);
- if (a && a != -1)
- return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
- return value & ((1 << n) - 1);
-}
-
-/*
* Extract/implement a data field from/to a little endian report (bit array).
*
* Code sort-of follows HID spec:
@@ -1873,9 +1865,12 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
/*
* 7 extra bytes are necessary to achieve proper functionality
* of implement() working on 8 byte chunks
+ * 1 extra byte for the report ID if it is null (not used) so
+ * we can reserve that extra byte in the first position of the buffer
+ * when sending it to .raw_request()
*/
- u32 len = hid_report_len(report) + 7;
+ u32 len = hid_report_len(report) + 7 + (report->id == 0);
return kzalloc(len, flags);
}
@@ -1963,7 +1958,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
int __hid_request(struct hid_device *hid, struct hid_report *report,
enum hid_class_request reqtype)
{
- char *buf;
+ char *buf, *data_buf;
int ret;
u32 len;
@@ -1971,13 +1966,19 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
if (!buf)
return -ENOMEM;
+ data_buf = buf;
len = hid_report_len(report);
+ if (report->id == 0) {
+ /* reserve the first byte for the report ID */
+ data_buf++;
+ len++;
+ }
+
if (reqtype == HID_REQ_SET_REPORT)
- hid_output_report(report, buf);
+ hid_output_report(report, data_buf);
- ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
- report->type, reqtype);
+ ret = hid_hw_raw_request(hid, report->id, buf, len, report->type, reqtype);
if (ret < 0) {
dbg_hid("unable to complete request: %d\n", ret);
goto out;
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 0fb210e40a41..9eafff0b6ea4 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -192,7 +192,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
goto cleanup;
input_device->report_desc_size = le16_to_cpu(
- desc->desc[0].wDescriptorLength);
+ desc->rpt_desc.wDescriptorLength);
if (input_device->report_desc_size == 0) {
input_device->dev_info_status = -EINVAL;
goto cleanup;
@@ -210,7 +210,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
memcpy(input_device->report_desc,
((unsigned char *)desc) + desc->bLength,
- le16_to_cpu(desc->desc[0].wDescriptorLength));
+ le16_to_cpu(desc->rpt_desc.wDescriptorLength));
/* Send the ack */
memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 92baa34f42f2..18c4e5f143a7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -41,6 +41,10 @@
#define USB_VENDOR_ID_ACTIONSTAR 0x2101
#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011
+#define USB_VENDOR_ID_ADATA_XPG 0x125f
+#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE 0x7505
+#define USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE 0x7506
+
#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
@@ -307,6 +311,8 @@
#define USB_DEVICE_ID_ASUS_AK1D 0x1125
#define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408
#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421
+#define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA 0xb824
+#define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2 0xb82c
#define USB_VENDOR_ID_CHUNGHWAT 0x2247
#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001
@@ -810,6 +816,7 @@
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
+#define USB_DEVICE_ID_LENOVO_X1_TAB2 0x60a4
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
@@ -818,6 +825,8 @@
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093
+#define USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT 0x6184
+#define USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT 0x61ed
#define USB_VENDOR_ID_LETSKETCH 0x6161
#define USB_DEVICE_ID_WP9620N 0x4d15
@@ -891,6 +900,7 @@
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
#define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
@@ -1514,4 +1524,7 @@
#define USB_VENDOR_ID_SIGNOTEC 0x2133
#define USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011 0x0018
+#define USB_VENDOR_ID_SMARTLINKTECHNOLOGY 0x4c4a
+#define USB_DEVICE_ID_SMARTLINKTECHNOLOGY_4155 0x4155
+
#endif
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
index 77c2d45ac62a..6f5c71660d82 100644
--- a/drivers/hid/hid-input-test.c
+++ b/drivers/hid/hid-input-test.c
@@ -7,7 +7,7 @@
#include <kunit/test.h>
-static void hid_test_input_set_battery_charge_status(struct kunit *test)
+static void hid_test_input_update_battery_charge_status(struct kunit *test)
{
struct hid_device *dev;
bool handled;
@@ -15,15 +15,15 @@ static void hid_test_input_set_battery_charge_status(struct kunit *test)
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
- handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0);
+ handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0);
KUNIT_EXPECT_FALSE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0);
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0);
KUNIT_EXPECT_TRUE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1);
+ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1);
KUNIT_EXPECT_TRUE(test, handled);
KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
}
@@ -63,7 +63,7 @@ static void hid_test_input_get_battery_property(struct kunit *test)
}
static struct kunit_case hid_input_tests[] = {
- KUNIT_CASE(hid_test_input_set_battery_charge_status),
+ KUNIT_CASE(hid_test_input_update_battery_charge_status),
KUNIT_CASE(hid_test_input_get_battery_property),
{ }
};
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 9d80635a91eb..f5c217ac4bfa 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -595,13 +595,33 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
dev->battery = NULL;
}
-static void hidinput_update_battery(struct hid_device *dev, int value)
+static bool hidinput_update_battery_charge_status(struct hid_device *dev,
+ unsigned int usage, int value)
+{
+ switch (usage) {
+ case HID_BAT_CHARGING:
+ dev->battery_charge_status = value ?
+ POWER_SUPPLY_STATUS_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
+ return true;
+ }
+
+ return false;
+}
+
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
+ int value)
{
int capacity;
if (!dev->battery)
return;
+ if (hidinput_update_battery_charge_status(dev, usage, value)) {
+ power_supply_changed(dev->battery);
+ return;
+ }
+
if (value == 0 || value < dev->battery_min || value > dev->battery_max)
return;
@@ -617,20 +637,6 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
power_supply_changed(dev->battery);
}
}
-
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
- unsigned int usage, int value)
-{
- switch (usage) {
- case HID_BAT_CHARGING:
- dev->battery_charge_status = value ?
- POWER_SUPPLY_STATUS_CHARGING :
- POWER_SUPPLY_STATUS_DISCHARGING;
- return true;
- }
-
- return false;
-}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
struct hid_field *field, bool is_percentage)
@@ -642,14 +648,9 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
{
}
-static void hidinput_update_battery(struct hid_device *dev, int value)
-{
-}
-
-static bool hidinput_set_battery_charge_status(struct hid_device *dev,
- unsigned int usage, int value)
+static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
+ int value)
{
- return false;
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
@@ -1515,11 +1516,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
if (usage->type == EV_PWR) {
- bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
-
- if (!handled)
- hidinput_update_battery(hid, value);
-
+ hidinput_update_battery(hid, usage->hid, value);
return;
}
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index f66194fde891..8482852c662d 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -473,6 +473,7 @@ static int lenovo_input_mapping(struct hid_device *hdev,
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
usage, bit, max);
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
default:
@@ -529,11 +530,14 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
/*
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
- * regular keys
+ * regular keys (Compact only)
*/
- ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
- if (ret)
- hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
+ if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
+ hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
+ ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
+ if (ret)
+ hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
+ }
/* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
@@ -584,6 +588,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
break;
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
ret = lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
if (ret)
@@ -778,6 +783,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_TP10UBKBD:
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
return lenovo_event_tp10ubkbd(hdev, field, usage, value);
default:
@@ -1059,6 +1065,7 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
break;
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
ret = lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
break;
@@ -1290,6 +1297,7 @@ static int lenovo_probe(struct hid_device *hdev,
break;
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
ret = lenovo_probe_tp10ubkbd(hdev);
break;
@@ -1377,6 +1385,7 @@ static void lenovo_remove(struct hid_device *hdev)
break;
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
case USB_DEVICE_ID_LENOVO_X1_TAB:
+ case USB_DEVICE_ID_LENOVO_X1_TAB2:
case USB_DEVICE_ID_LENOVO_X1_TAB3:
lenovo_remove_tp10ubkbd(hdev);
break;
@@ -1428,6 +1437,8 @@ static const struct hid_device_id lenovo_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+ USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB2) },
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
{ }
};
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 34fa71ceec2b..cce54dd9884a 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1983,6 +1983,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
.driver_data = recvr_type_gaming_hidpp},
+ { /* Logitech lightspeed receiver (0xc543) */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2),
+ .driver_data = recvr_type_gaming_hidpp},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index cf7a6986cf20..59f630962338 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -3296,13 +3296,13 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
120);
}
- v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12);
+ v = sign_extend32(hid_field_extract(hdev, data + 3, 0, 12), 11);
input_report_rel(hidpp->input, REL_X, v);
- v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12);
+ v = sign_extend32(hid_field_extract(hdev, data + 3, 12, 12), 11);
input_report_rel(hidpp->input, REL_Y, v);
- v = hid_snto32(data[6], 8);
+ v = sign_extend32(data[6], 7);
if (v != 0)
hidpp_scroll_counter_handle_scroll(hidpp->input,
&hidpp->vertical_wheel_counter, v);
@@ -4624,6 +4624,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
{ /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) },
+ { /* Logitech G PRO 2 LIGHTSPEED Wireless Mouse over USB */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xc09a) },
{ /* G935 Gaming Headset */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index ec110dea8772..542b3e86d56f 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -775,16 +775,30 @@ static void magicmouse_enable_mt_work(struct work_struct *work)
hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
}
+static bool is_usb_magicmouse2(__u32 vendor, __u32 product)
+{
+ if (vendor != USB_VENDOR_ID_APPLE)
+ return false;
+ return product == USB_DEVICE_ID_APPLE_MAGICMOUSE2;
+}
+
+static bool is_usb_magictrackpad2(__u32 vendor, __u32 product)
+{
+ if (vendor != USB_VENDOR_ID_APPLE)
+ return false;
+ return product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
+ product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC;
+}
+
static int magicmouse_fetch_battery(struct hid_device *hdev)
{
#ifdef CONFIG_HID_BATTERY_STRENGTH
struct hid_report_enum *report_enum;
struct hid_report *report;
- if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
- (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
- hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
- hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC))
+ if (!hdev->battery ||
+ (!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
+ !is_usb_magictrackpad2(hdev->vendor, hdev->product)))
return -1;
report_enum = &hdev->report_enum[hdev->battery_report_type];
@@ -846,16 +860,17 @@ static int magicmouse_probe(struct hid_device *hdev,
return ret;
}
- timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
- mod_timer(&msc->battery_timer,
- jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
- magicmouse_fetch_battery(hdev);
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ is_usb_magictrackpad2(id->vendor, id->product)) {
+ timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
+ mod_timer(&msc->battery_timer,
+ jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
+ magicmouse_fetch_battery(hdev);
+ }
- if (id->vendor == USB_VENDOR_ID_APPLE &&
- (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
- ((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
- id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
- hdev->type != HID_TYPE_USBMOUSE)))
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ (is_usb_magictrackpad2(id->vendor, id->product) &&
+ hdev->type != HID_TYPE_USBMOUSE))
return 0;
if (!msc->input) {
@@ -911,7 +926,10 @@ static int magicmouse_probe(struct hid_device *hdev,
return 0;
err_stop_hw:
- del_timer_sync(&msc->battery_timer);
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ is_usb_magictrackpad2(id->vendor, id->product))
+ del_timer_sync(&msc->battery_timer);
+
hid_hw_stop(hdev);
return ret;
}
@@ -922,7 +940,9 @@ static void magicmouse_remove(struct hid_device *hdev)
if (msc) {
cancel_delayed_work_sync(&msc->work);
- del_timer_sync(&msc->battery_timer);
+ if (is_usb_magicmouse2(hdev->vendor, hdev->product) ||
+ is_usb_magictrackpad2(hdev->vendor, hdev->product))
+ del_timer_sync(&msc->battery_timer);
}
hid_hw_stop(hdev);
@@ -939,10 +959,8 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
* 0x09, 0x02, // Usage (Mouse) 2
*/
- if (hdev->vendor == USB_VENDOR_ID_APPLE &&
- (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
- hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
- hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
+ if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
+ is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
*rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
hid_info(hdev,
"fixing up magicmouse battery report descriptor\n");
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 93b5c648ef82..5c424010bc02 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1453,6 +1453,14 @@ static const __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
(hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {
+ if (*size < 608) {
+ dev_info(
+ &hdev->dev,
+ "GT7868Q fixup: report descriptor is only %u bytes, skipping\n",
+ *size);
+ return rdesc;
+ }
+
if (rdesc[607] == 0x15) {
rdesc[607] = 0x25;
dev_info(
@@ -2116,12 +2124,18 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC,
USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) },
- /* Lenovo X1 TAB Gen 2 */
+ /* Lenovo X1 TAB Gen 1 */
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X1_TAB) },
+ /* Lenovo X1 TAB Gen 2 */
+ { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_LENOVO,
+ USB_DEVICE_ID_LENOVO_X1_TAB2) },
+
/* Lenovo X1 TAB Gen 3 */
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index 55153a2f7988..2a3ae1068739 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -308,6 +308,7 @@ enum joycon_ctlr_state {
JOYCON_CTLR_STATE_INIT,
JOYCON_CTLR_STATE_READ,
JOYCON_CTLR_STATE_REMOVED,
+ JOYCON_CTLR_STATE_SUSPENDED,
};
/* Controller type received as part of device info */
@@ -2754,14 +2755,46 @@ static void nintendo_hid_remove(struct hid_device *hdev)
static int nintendo_hid_resume(struct hid_device *hdev)
{
- int ret = joycon_init(hdev);
+ struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
+ int ret;
+
+ hid_dbg(hdev, "resume\n");
+ if (!joycon_using_usb(ctlr)) {
+ hid_dbg(hdev, "no-op resume for bt ctlr\n");
+ ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
+ return 0;
+ }
+ ret = joycon_init(hdev);
if (ret)
- hid_err(hdev, "Failed to restore controller after resume");
+ hid_err(hdev,
+ "Failed to restore controller after resume: %d\n",
+ ret);
+ else
+ ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
return ret;
}
+static int nintendo_hid_suspend(struct hid_device *hdev, pm_message_t message)
+{
+ struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
+
+ hid_dbg(hdev, "suspend: %d\n", message.event);
+ /*
+ * Avoid any blocking loops in suspend/resume transitions.
+ *
+ * joycon_enforce_subcmd_rate() can result in repeated retries if for
+ * whatever reason the controller stops providing input reports.
+ *
+ * This has been observed with bluetooth controllers which lose
+ * connectivity prior to suspend (but not long enough to result in
+ * complete disconnection).
+ */
+ ctlr->ctlr_state = JOYCON_CTLR_STATE_SUSPENDED;
+ return 0;
+}
+
#endif
static const struct hid_device_id nintendo_hid_devices[] = {
@@ -2800,6 +2833,7 @@ static struct hid_driver nintendo_hid_driver = {
#ifdef CONFIG_PM
.resume = nintendo_hid_resume,
+ .suspend = nintendo_hid_suspend,
#endif
};
static int __init nintendo_init(void)
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 2738ce947434..0f76e241e0af 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev)
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
unsigned char *data = kmalloc(8, GFP_KERNEL);
+ if (!hid_is_usb(hdev))
+ return;
+
if (!data)
goto err_free;
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 5d7a418ccdbe..64f9728018b8 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -27,6 +27,8 @@
static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE_DONGLE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016), HID_QUIRK_FULLSPEED_INTERVAL },
{ HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX), HID_QUIRK_NO_INIT_REPORTS },
@@ -122,6 +124,8 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
@@ -745,6 +749,8 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },
@@ -892,6 +898,7 @@ static const struct hid_device_id hid_ignore_list[] = {
#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_HP_5MP_CAMERA_5473) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SMARTLINKTECHNOLOGY, USB_DEVICE_ID_SMARTLINKTECHNOLOGY_4155) },
{ }
};
diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c
index 3b81468a1df2..0bf70664c35e 100644
--- a/drivers/hid/hid-thrustmaster.c
+++ b/drivers/hid/hid-thrustmaster.c
@@ -174,6 +174,7 @@ static void thrustmaster_interrupts(struct hid_device *hdev)
u8 ep_addr[2] = {b_ep, 0};
if (!usb_check_int_endpoints(usbif, ep_addr)) {
+ kfree(send_buf);
hid_err(hdev, "Unexpected non-int endpoint\n");
return;
}
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index d8008933c052..321c43fb06ae 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -142,11 +142,12 @@ static int uclogic_input_configured(struct hid_device *hdev,
suffix = "System Control";
break;
}
- }
-
- if (suffix)
+ } else {
hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
"%s %s", hdev->name, suffix);
+ if (!hi->input->name)
+ return -ENOMEM;
+ }
return 0;
}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index bf0f51ef0149..01625dbb28e8 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -984,12 +984,11 @@ static int usbhid_parse(struct hid_device *hid)
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
+ struct hid_class_descriptor *hcdesc;
u32 quirks = 0;
unsigned int rsize = 0;
char *rdesc;
- int ret, n;
- int num_descriptors;
- size_t offset = offsetof(struct hid_descriptor, desc);
+ int ret;
quirks = hid_lookup_quirk(hid);
@@ -1011,20 +1010,19 @@ static int usbhid_parse(struct hid_device *hid)
return -ENODEV;
}
- if (hdesc->bLength < sizeof(struct hid_descriptor)) {
- dbg_hid("hid descriptor is too short\n");
+ if (!hdesc->bNumDescriptors ||
+ hdesc->bLength != sizeof(*hdesc) +
+ (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
+ dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
+ hdesc->bLength, hdesc->bNumDescriptors);
return -EINVAL;
}
hid->version = le16_to_cpu(hdesc->bcdHID);
hid->country = hdesc->bCountryCode;
- num_descriptors = min_t(int, hdesc->bNumDescriptors,
- (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
-
- for (n = 0; n < num_descriptors; n++)
- if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
- rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
+ if (hdesc->rpt_desc.bDescriptorType == HID_DT_REPORT)
+ rsize = le16_to_cpu(hdesc->rpt_desc.wDescriptorLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
dbg_hid("weird size of report descriptor (%u)\n", rsize);
@@ -1052,6 +1050,11 @@ static int usbhid_parse(struct hid_device *hid)
goto err;
}
+ if (hdesc->bNumDescriptors > 1)
+ hid_warn(intf,
+ "%u unsupported optional hid class descriptors\n",
+ (int)(hdesc->bNumDescriptors - 1));
+
hid->quirks |= quirks;
return 0;
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index c439ed2f16db..af6bc76dbf64 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -160,7 +160,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
return -1;
spin_lock_irqsave(&kbd->leds_lock, flags);
- kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+ kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 4) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 34428349fa31..1b1112772777 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -2021,14 +2021,18 @@ static int wacom_initialize_remotes(struct wacom *wacom)
remote->remote_dir = kobject_create_and_add("wacom_remote",
&wacom->hdev->dev.kobj);
- if (!remote->remote_dir)
+ if (!remote->remote_dir) {
+ kfifo_free(&remote->remote_fifo);
return -ENOMEM;
+ }
error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);
if (error) {
hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error);
+ kfifo_free(&remote->remote_fifo);
+ kobject_put(remote->remote_dir);
return error;
}
@@ -2874,6 +2878,7 @@ static void wacom_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
cancel_delayed_work_sync(&wacom->init_work);
+ cancel_delayed_work_sync(&wacom->aes_battery_work);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index c7033ffaba39..a076dc0b60ee 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -684,6 +684,7 @@ static bool wacom_is_art_pen(int tool_id)
case 0x885: /* Intuos3 Marker Pen */
case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */
+ case 0x204: /* Art Pen 2 */
is_art_pen = true;
break;
}