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
This commit is contained in:
commit
fc3abb5325
|
@ -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
|
||||
* hid_alloc_report_buf() so that it has proper size.
|
||||
|
@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
|
|||
if (report->id > 0)
|
||||
*data++ = report->id;
|
||||
|
||||
memset(data, 0, ((report->size - 1) >> 3) + 1);
|
||||
memset(data, 0, hid_compute_report_size(report));
|
||||
for (n = 0; n < report->maxfield; n++)
|
||||
hid_output_field(report->device, report->field[n], data);
|
||||
}
|
||||
|
@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
|||
csize--;
|
||||
}
|
||||
|
||||
rsize = ((report->size - 1) >> 3) + 1;
|
||||
rsize = hid_compute_report_size(report);
|
||||
|
||||
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
|
||||
rsize = HID_MAX_BUFFER_SIZE - 1;
|
||||
|
|
|
@ -188,6 +188,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
|
||||
input_free_device(input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -198,6 +199,7 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
if (ret) {
|
||||
hid_err(hdev, "Failed to register elan input device: %d\n",
|
||||
ret);
|
||||
input_mt_destroy_slots(input);
|
||||
input_free_device(input);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -850,6 +850,7 @@
|
|||
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
||||
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
|
||||
#define USB_DEVICE_ID_MS_PIXART_MOUSE 0x00cb
|
||||
#define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS 0x02e0
|
||||
|
||||
#define USB_VENDOR_ID_MOJO 0x8282
|
||||
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
|
||||
|
@ -1015,6 +1016,8 @@
|
|||
#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa
|
||||
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
|
||||
#define USB_DEVICE_ID_SAITEK_X52 0x075c
|
||||
#define USB_DEVICE_ID_SAITEK_X52_2 0x0255
|
||||
#define USB_DEVICE_ID_SAITEK_X52_PRO 0x0762
|
||||
|
||||
#define USB_VENDOR_ID_SAMSUNG 0x0419
|
||||
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
|
||||
|
|
|
@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
}
|
||||
|
||||
mapped:
|
||||
/* Mapping failed, bail out */
|
||||
if (!bit)
|
||||
return;
|
||||
|
||||
if (device->driver->input_mapped &&
|
||||
device->driver->input_mapped(device, hidinput, field, usage,
|
||||
&bit, &max) < 0) {
|
||||
|
|
|
@ -448,6 +448,8 @@ static const struct hid_device_id ms_devices[] = {
|
|||
.driver_data = MS_SURFACE_DIAL },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
|
||||
.driver_data = MS_QUIRK_FF },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS),
|
||||
.driver_data = MS_QUIRK_FF },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, ms_devices);
|
||||
|
|
|
@ -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);
|
||||
|
||||
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
|
||||
if (!*bit)
|
||||
return -1;
|
||||
input_set_capability(hi->input, EV_KEY, code);
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -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_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
|
||||
|
|
|
@ -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)
|
||||
* @type: input event type (EV_KEY, EV_REL, ...)
|
||||
* @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,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max,
|
||||
__u8 type, __u16 c)
|
||||
__u8 type, unsigned int c)
|
||||
{
|
||||
struct input_dev *input = hidinput->input;
|
||||
|
||||
usage->type = type;
|
||||
usage->code = c;
|
||||
unsigned long *bmap = NULL;
|
||||
unsigned int limit = 0;
|
||||
|
||||
switch (type) {
|
||||
case EV_ABS:
|
||||
*bit = input->absbit;
|
||||
*max = ABS_MAX;
|
||||
bmap = input->absbit;
|
||||
limit = ABS_MAX;
|
||||
break;
|
||||
case EV_REL:
|
||||
*bit = input->relbit;
|
||||
*max = REL_MAX;
|
||||
bmap = input->relbit;
|
||||
limit = REL_MAX;
|
||||
break;
|
||||
case EV_KEY:
|
||||
*bit = input->keybit;
|
||||
*max = KEY_MAX;
|
||||
bmap = input->keybit;
|
||||
limit = KEY_MAX;
|
||||
break;
|
||||
case EV_LED:
|
||||
*bit = input->ledbit;
|
||||
*max = LED_MAX;
|
||||
bmap = input->ledbit;
|
||||
limit = LED_MAX;
|
||||
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,
|
|||
__u8 type, __u16 c)
|
||||
{
|
||||
hid_map_usage(hidinput, usage, bit, max, type, c);
|
||||
clear_bit(c, *bit);
|
||||
if (*bit)
|
||||
clear_bit(usage->code, *bit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user