Commit fc3abb53 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID fixes from Jiri Kosina:

 - data sanitization and validtion fixes for report descriptor parser
   from Marc Zyngier

 - memory leak fix for hid-elan driver from Dinghao Liu

 - two device-specific quirks

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: core: Sanitize event code and type when mapping input
  HID: core: Correctly handle ReportSize being zero
  HID: elan: Fix memleak in elan_input_configured
  HID: microsoft: Add rumble support for the 8bitdo SN30 Pro+ controller
  HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for all Saitek X52 devices
parents c3a13095 35556bed
...@@ -1597,6 +1597,17 @@ static void hid_output_field(const struct hid_device *hid, ...@@ -1597,6 +1597,17 @@ static void hid_output_field(const struct hid_device *hid,
} }
} }
/*
* Compute the size of a report.
*/
static size_t hid_compute_report_size(struct hid_report *report)
{
if (report->size)
return ((report->size - 1) >> 3) + 1;
return 0;
}
/* /*
* Create a report. 'data' has to be allocated using * Create a report. 'data' has to be allocated using
* hid_alloc_report_buf() so that it has proper size. * hid_alloc_report_buf() so that it has proper size.
...@@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data) ...@@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
if (report->id > 0) if (report->id > 0)
*data++ = report->id; *data++ = report->id;
memset(data, 0, ((report->size - 1) >> 3) + 1); memset(data, 0, hid_compute_report_size(report));
for (n = 0; n < report->maxfield; n++) for (n = 0; n < report->maxfield; n++)
hid_output_field(report->device, report->field[n], data); hid_output_field(report->device, report->field[n], data);
} }
...@@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, ...@@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
csize--; csize--;
} }
rsize = ((report->size - 1) >> 3) + 1; rsize = hid_compute_report_size(report);
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE) if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
rsize = HID_MAX_BUFFER_SIZE - 1; rsize = HID_MAX_BUFFER_SIZE - 1;
......
...@@ -188,6 +188,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -188,6 +188,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER); ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
if (ret) { if (ret) {
hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
input_free_device(input);
return ret; return ret;
} }
...@@ -198,6 +199,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -198,6 +199,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret) { if (ret) {
hid_err(hdev, "Failed to register elan input device: %d\n", hid_err(hdev, "Failed to register elan input device: %d\n",
ret); ret);
input_mt_destroy_slots(input);
input_free_device(input); input_free_device(input);
return ret; return ret;
} }
......
...@@ -850,6 +850,7 @@ ...@@ -850,6 +850,7 @@
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_DEVICE_ID_MS_POWER_COVER 0x07da
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
#define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb #define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb
#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS 0x02e0
#define USB_VENDOR_ID_MOJO 0x8282 #define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
...@@ -1015,6 +1016,8 @@ ...@@ -1015,6 +1016,8 @@
#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa #define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0 #define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
#define USB_DEVICE_ID_SAITEK_X52 0x075c #define USB_DEVICE_ID_SAITEK_X52 0x075c
#define USB_DEVICE_ID_SAITEK_X52_2 0x0255
#define USB_DEVICE_ID_SAITEK_X52_PRO 0x0762
#define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
......
...@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
mapped: mapped:
/* Mapping failed, bail out */
if (!bit)
return;
if (device->driver->input_mapped && if (device->driver->input_mapped &&
device->driver->input_mapped(device, hidinput, field, usage, device->driver->input_mapped(device, hidinput, field, usage,
&bit, &max) < 0) { &bit, &max) < 0) {
......
...@@ -448,6 +448,8 @@ static const struct hid_device_id ms_devices[] = { ...@@ -448,6 +448,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_SURFACE_DIAL }, .driver_data = MS_SURFACE_DIAL },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER), { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
.driver_data = MS_QUIRK_FF }, .driver_data = MS_QUIRK_FF },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS),
.driver_data = MS_QUIRK_FF },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, ms_devices); MODULE_DEVICE_TABLE(hid, ms_devices);
......
...@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
code = BTN_0 + ((usage->hid - 1) & HID_USAGE); code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
hid_map_usage(hi, usage, bit, max, EV_KEY, code); hid_map_usage(hi, usage, bit, max, EV_KEY, code);
if (!*bit)
return -1;
input_set_capability(hi->input, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code);
return 1; return 1;
......
...@@ -150,6 +150,8 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -150,6 +150,8 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
......
...@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) { ...@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) {
* @max: maximal valid usage->code to consider later (out parameter) * @max: maximal valid usage->code to consider later (out parameter)
* @type: input event type (EV_KEY, EV_REL, ...) * @type: input event type (EV_KEY, EV_REL, ...)
* @c: code which corresponds to this usage and type * @c: code which corresponds to this usage and type
*
* The value pointed to by @bit will be set to NULL if either @type is
* an unhandled event type, or if @c is out of range for @type. This
* can be used as an error condition.
*/ */
static inline void hid_map_usage(struct hid_input *hidinput, static inline void hid_map_usage(struct hid_input *hidinput,
struct hid_usage *usage, unsigned long **bit, int *max, struct hid_usage *usage, unsigned long **bit, int *max,
__u8 type, __u16 c) __u8 type, unsigned int c)
{ {
struct input_dev *input = hidinput->input; struct input_dev *input = hidinput->input;
unsigned long *bmap = NULL;
usage->type = type; unsigned int limit = 0;
usage->code = c;
switch (type) { switch (type) {
case EV_ABS: case EV_ABS:
*bit = input->absbit; bmap = input->absbit;
*max = ABS_MAX; limit = ABS_MAX;
break; break;
case EV_REL: case EV_REL:
*bit = input->relbit; bmap = input->relbit;
*max = REL_MAX; limit = REL_MAX;
break; break;
case EV_KEY: case EV_KEY:
*bit = input->keybit; bmap = input->keybit;
*max = KEY_MAX; limit = KEY_MAX;
break; break;
case EV_LED: case EV_LED:
*bit = input->ledbit; bmap = input->ledbit;
*max = LED_MAX; limit = LED_MAX;
break; break;
} }
if (unlikely(c > limit || !bmap)) {
pr_warn_ratelimited("%s: Invalid code %d type %d\n",
input->name, c, type);
*bit = NULL;
return;
}
usage->type = type;
usage->code = c;
*max = limit;
*bit = bmap;
} }
/** /**
...@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput, ...@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
__u8 type, __u16 c) __u8 type, __u16 c)
{ {
hid_map_usage(hidinput, usage, bit, max, type, c); hid_map_usage(hidinput, usage, bit, max, type, c);
clear_bit(c, *bit); if (*bit)
clear_bit(usage->code, *bit);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment