mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 21:21:49 -04:00
Merge tag 'hid-for-linus-2026051401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID fixes from Jiri Kosina: - fixes for a few OOB/UAF in several HID drivers (Florian Pradines, Lee Jones, Michael Zaidman, Rosalie Wanders, Sangyun Kim and Tomasz Pakuła) - more general sanitation of input data, dealing with potentially malicious hardware in hid-core (Benjamin Tissoires) - a few device-specific quirks and fixups * tag 'hid-for-linus-2026051401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (22 commits) HID: logitech-hidpp: Add support for newer Bluetooth keyboards HID: pidff: Fix integer overflow in pidff_rescale HID: i2c-hid: add reset quirk for BLTP7853 touchpad HID: core: introduce hid_safe_input_report() HID: pass the buffer size to hid_report_raw_event HID: google: hammer: stop hardware on devres action failure HID: appletb-kbd: run inactivity autodim from workqueues HID: appletb-kbd: fix UAF in inactivity-timer cleanup path HID: playstation: Clamp num_touch_reports HID: magicmouse: Prevent out-of-bounds (OOB) read during DOUBLE_REPORT_ID HID: mcp2221: fix OOB write in mcp2221_raw_event() HID: quirks: really enable the intended work around for appledisplay HID: hid-sjoy: race between init and usage HID: uclogic: Fix regression of input name assignment HID: intel-thc-hid: Intel-quickspi: Fix some error codes HID: hid-lenovo-go-s: restore OS_TYPE after resume from s2idle HID: elan: Add support for ELAN SB974D touchpad HID: sony: add missing size validation for Rock Band 3 Pro instruments HID: sony: add missing size validation for SMK-Link remotes HID: sony: remove unneeded WARN_ON() in sony_leds_init() ...
This commit is contained in:
@@ -24,7 +24,8 @@ EXPORT_SYMBOL(hid_ops);
|
||||
|
||||
u8 *
|
||||
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
|
||||
u32 *size, int interrupt, u64 source, bool from_bpf)
|
||||
size_t *buf_size, u32 *size, int interrupt, u64 source,
|
||||
bool from_bpf)
|
||||
{
|
||||
struct hid_bpf_ctx_kern ctx_kern = {
|
||||
.ctx = {
|
||||
@@ -74,6 +75,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
|
||||
*size = ret;
|
||||
}
|
||||
|
||||
*buf_size = ctx_kern.ctx.allocated_size;
|
||||
return ctx_kern.data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
|
||||
@@ -505,7 +507,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *b
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (u64)(long)ctx, true,
|
||||
return hid_ops->hid_input_report(ctx->hid, type, buf, size, size, 0, (u64)(long)ctx, true,
|
||||
lock_already_taken);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
@@ -62,7 +62,8 @@ struct appletb_kbd {
|
||||
struct input_handle kbd_handle;
|
||||
struct input_handle tpd_handle;
|
||||
struct backlight_device *backlight_dev;
|
||||
struct timer_list inactivity_timer;
|
||||
struct delayed_work inactivity_work;
|
||||
struct work_struct restore_brightness_work;
|
||||
bool has_dimmed;
|
||||
bool has_turned_off;
|
||||
u8 saved_mode;
|
||||
@@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
|
||||
}
|
||||
}
|
||||
|
||||
static void appletb_inactivity_timer(struct timer_list *t)
|
||||
static void appletb_inactivity_work(struct work_struct *work)
|
||||
{
|
||||
struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
|
||||
struct appletb_kbd *kbd = container_of(to_delayed_work(work),
|
||||
struct appletb_kbd,
|
||||
inactivity_work);
|
||||
|
||||
if (kbd->backlight_dev && appletb_tb_autodim) {
|
||||
if (!kbd->has_dimmed) {
|
||||
backlight_device_set_brightness(kbd->backlight_dev, 1);
|
||||
kbd->has_dimmed = true;
|
||||
mod_timer(&kbd->inactivity_timer,
|
||||
jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
|
||||
mod_delayed_work(system_wq, &kbd->inactivity_work,
|
||||
secs_to_jiffies(appletb_tb_idle_timeout));
|
||||
} else if (!kbd->has_turned_off) {
|
||||
backlight_device_set_brightness(kbd->backlight_dev, 0);
|
||||
kbd->has_turned_off = true;
|
||||
@@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
|
||||
}
|
||||
}
|
||||
|
||||
static void appletb_restore_brightness_work(struct work_struct *work)
|
||||
{
|
||||
struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
|
||||
restore_brightness_work);
|
||||
|
||||
if (kbd->backlight_dev)
|
||||
backlight_device_set_brightness(kbd->backlight_dev, 2);
|
||||
}
|
||||
|
||||
static void reset_inactivity_timer(struct appletb_kbd *kbd)
|
||||
{
|
||||
if (kbd->backlight_dev && appletb_tb_autodim) {
|
||||
if (kbd->has_dimmed || kbd->has_turned_off) {
|
||||
backlight_device_set_brightness(kbd->backlight_dev, 2);
|
||||
kbd->has_dimmed = false;
|
||||
kbd->has_turned_off = false;
|
||||
schedule_work(&kbd->restore_brightness_work);
|
||||
}
|
||||
mod_timer(&kbd->inactivity_timer,
|
||||
jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
|
||||
mod_delayed_work(system_wq, &kbd->inactivity_work,
|
||||
secs_to_jiffies(appletb_tb_dim_timeout));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
|
||||
} else {
|
||||
backlight_device_set_brightness(kbd->backlight_dev, 2);
|
||||
timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
|
||||
mod_timer(&kbd->inactivity_timer,
|
||||
jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
|
||||
INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
|
||||
INIT_WORK(&kbd->restore_brightness_work,
|
||||
appletb_restore_brightness_work);
|
||||
mod_delayed_work(system_wq, &kbd->inactivity_work,
|
||||
secs_to_jiffies(appletb_tb_dim_timeout));
|
||||
}
|
||||
|
||||
kbd->inp_handler.event = appletb_kbd_inp_event;
|
||||
@@ -440,13 +454,14 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
unregister_handler:
|
||||
input_unregister_handler(&kbd->inp_handler);
|
||||
close_hw:
|
||||
if (kbd->backlight_dev) {
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
timer_delete_sync(&kbd->inactivity_timer);
|
||||
}
|
||||
hid_hw_close(hdev);
|
||||
stop_hw:
|
||||
hid_hw_stop(hdev);
|
||||
if (kbd->backlight_dev) {
|
||||
cancel_delayed_work_sync(&kbd->inactivity_work);
|
||||
cancel_work_sync(&kbd->restore_brightness_work);
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -457,13 +472,14 @@ static void appletb_kbd_remove(struct hid_device *hdev)
|
||||
appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
|
||||
|
||||
input_unregister_handler(&kbd->inp_handler);
|
||||
if (kbd->backlight_dev) {
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
timer_delete_sync(&kbd->inactivity_timer);
|
||||
}
|
||||
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
|
||||
if (kbd->backlight_dev) {
|
||||
cancel_delayed_work_sync(&kbd->inactivity_work);
|
||||
cancel_work_sync(&kbd->restore_brightness_work);
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
|
||||
|
||||
@@ -2033,24 +2033,32 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hid_request);
|
||||
|
||||
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt)
|
||||
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
|
||||
size_t bufsize, u32 size, int interrupt)
|
||||
{
|
||||
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||||
struct hid_report *report;
|
||||
struct hid_driver *hdrv;
|
||||
int max_buffer_size = HID_MAX_BUFFER_SIZE;
|
||||
u32 rsize, csize = size;
|
||||
size_t bsize = bufsize;
|
||||
u8 *cdata = data;
|
||||
int ret = 0;
|
||||
|
||||
report = hid_get_report(report_enum, data);
|
||||
if (!report)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
if (unlikely(bsize < csize)) {
|
||||
hid_warn_ratelimited(hid, "Event data for report %d is incorrect (%d vs %ld)\n",
|
||||
report->id, csize, bsize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (report_enum->numbered) {
|
||||
cdata++;
|
||||
csize--;
|
||||
bsize--;
|
||||
}
|
||||
|
||||
rsize = hid_compute_report_size(report);
|
||||
@@ -2063,11 +2071,16 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
|
||||
else if (rsize > max_buffer_size)
|
||||
rsize = max_buffer_size;
|
||||
|
||||
if (bsize < rsize) {
|
||||
hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %ld)\n",
|
||||
report->id, rsize, bsize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (csize < rsize) {
|
||||
hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
|
||||
report->id, rsize, csize);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
dbg_hid("report %d is too short, (%d < %d)\n", report->id,
|
||||
csize, rsize);
|
||||
memset(cdata + csize, 0, rsize - csize);
|
||||
}
|
||||
|
||||
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
|
||||
@@ -2075,7 +2088,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
|
||||
if (hid->claimed & HID_CLAIMED_HIDRAW) {
|
||||
ret = hidraw_report_event(hid, data, size);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
|
||||
@@ -2087,15 +2100,15 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
|
||||
|
||||
if (hid->claimed & HID_CLAIMED_INPUT)
|
||||
hidinput_report_event(hid, report);
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_report_raw_event);
|
||||
|
||||
|
||||
static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
|
||||
u8 *data, u32 size, int interrupt, u64 source, bool from_bpf,
|
||||
bool lock_already_taken)
|
||||
u8 *data, size_t bufsize, u32 size, int interrupt, u64 source,
|
||||
bool from_bpf, bool lock_already_taken)
|
||||
{
|
||||
struct hid_report_enum *report_enum;
|
||||
struct hid_driver *hdrv;
|
||||
@@ -2120,7 +2133,8 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
|
||||
report_enum = hid->report_enum + type;
|
||||
hdrv = hid->driver;
|
||||
|
||||
data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source, from_bpf);
|
||||
data = dispatch_hid_bpf_device_event(hid, type, data, &bufsize, &size, interrupt,
|
||||
source, from_bpf);
|
||||
if (IS_ERR(data)) {
|
||||
ret = PTR_ERR(data);
|
||||
goto unlock;
|
||||
@@ -2149,7 +2163,7 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = hid_report_raw_event(hid, type, data, size, interrupt);
|
||||
ret = hid_report_raw_event(hid, type, data, bufsize, size, interrupt);
|
||||
|
||||
unlock:
|
||||
if (!lock_already_taken)
|
||||
@@ -2167,16 +2181,41 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
|
||||
* @interrupt: distinguish between interrupt and control transfers
|
||||
*
|
||||
* This is data entry for lower layers.
|
||||
* Legacy, please use hid_safe_input_report() instead.
|
||||
*/
|
||||
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt)
|
||||
{
|
||||
return __hid_input_report(hid, type, data, size, interrupt, 0,
|
||||
return __hid_input_report(hid, type, data, size, size, interrupt, 0,
|
||||
false, /* from_bpf */
|
||||
false /* lock_already_taken */);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_input_report);
|
||||
|
||||
/**
|
||||
* hid_safe_input_report - report data from lower layer (usb, bt...)
|
||||
*
|
||||
* @hid: hid device
|
||||
* @type: HID report type (HID_*_REPORT)
|
||||
* @data: report contents
|
||||
* @bufsize: allocated size of the data buffer
|
||||
* @size: useful size of data parameter
|
||||
* @interrupt: distinguish between interrupt and control transfers
|
||||
*
|
||||
* This is data entry for lower layers.
|
||||
* Please use this function instead of the non safe version because we provide
|
||||
* here the size of the buffer, allowing hid-core to make smarter decisions
|
||||
* regarding the incoming buffer.
|
||||
*/
|
||||
int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
|
||||
size_t bufsize, u32 size, int interrupt)
|
||||
{
|
||||
return __hid_input_report(hid, type, data, bufsize, size, interrupt, 0,
|
||||
false, /* from_bpf */
|
||||
false /* lock_already_taken */);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_safe_input_report);
|
||||
|
||||
bool hid_match_one_id(const struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
|
||||
@@ -513,6 +513,7 @@ static const struct hid_device_id elan_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER),
|
||||
.driver_data = ELAN_HAS_LED },
|
||||
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_TOSHIBA_CLICK_L9W) },
|
||||
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_SB974D) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, elan_devices);
|
||||
|
||||
@@ -1068,10 +1068,22 @@ static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
struct ft260_device *dev = hid_get_drvdata(hdev);
|
||||
struct ft260_i2c_input_report *xfer = (void *)data;
|
||||
|
||||
if (size < offsetof(struct ft260_i2c_input_report, data)) {
|
||||
hid_err(hdev, "short report %d\n", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfer->report >= FT260_I2C_REPORT_MIN &&
|
||||
xfer->report <= FT260_I2C_REPORT_MAX) {
|
||||
ft260_dbg("i2c resp: rep %#02x len %d\n", xfer->report,
|
||||
xfer->length);
|
||||
ft260_dbg("i2c resp: rep %#02x len %d size %d\n",
|
||||
xfer->report, xfer->length, size);
|
||||
|
||||
if (xfer->length > size -
|
||||
offsetof(struct ft260_i2c_input_report, data)) {
|
||||
hid_err(hdev, "report %#02x: length %d exceeds HID report size\n",
|
||||
xfer->report, xfer->length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((dev->read_buf == NULL) ||
|
||||
(xfer->length > dev->read_len - dev->read_idx)) {
|
||||
|
||||
@@ -66,7 +66,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
switch (data[1]) {
|
||||
case GFRM100_SEARCH_KEY_DOWN:
|
||||
ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn,
|
||||
sizeof(search_key_dn), 1);
|
||||
sizeof(search_key_dn), sizeof(search_key_dn), 1);
|
||||
break;
|
||||
|
||||
case GFRM100_SEARCH_KEY_AUDIO_DATA:
|
||||
@@ -74,7 +74,7 @@ static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
|
||||
case GFRM100_SEARCH_KEY_UP:
|
||||
ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up,
|
||||
sizeof(search_key_up), 1);
|
||||
sizeof(search_key_up), sizeof(search_key_up), 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -496,7 +496,7 @@ static int hammer_probe(struct hid_device *hdev,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = devm_add_action(&hdev->dev, hammer_stop, hdev);
|
||||
error = devm_add_action_or_reset(&hdev->dev, hammer_stop, hdev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
||||
@@ -277,6 +277,9 @@
|
||||
#define USB_VENDOR_ID_BIGBEN 0x146b
|
||||
#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902
|
||||
|
||||
#define I2C_VENDOR_ID_BLTP 0x36b6
|
||||
#define I2C_PRODUCT_ID_BLTP7853 0xc001
|
||||
|
||||
#define USB_VENDOR_ID_BTC 0x046e
|
||||
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
|
||||
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
|
||||
@@ -455,6 +458,7 @@
|
||||
#define USB_DEVICE_ID_EDIFIER_QR30 0xa101 /* EDIFIER Hal0 2.0 SE */
|
||||
|
||||
#define USB_VENDOR_ID_ELAN 0x04f3
|
||||
#define USB_DEVICE_ID_SB974D 0x0400
|
||||
#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
|
||||
#define USB_DEVICE_ID_HP_X2 0x074d
|
||||
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
|
||||
|
||||
@@ -1369,6 +1369,14 @@ static void cfg_setup(struct work_struct *work)
|
||||
"Failed to retrieve IMU Manufacturer: %i\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG, FEATURE_OS_MODE,
|
||||
NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&drvdata.hdev->dev,
|
||||
"Failed to retrieve OS Mode: %i\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int hid_gos_cfg_probe(struct hid_device *hdev,
|
||||
@@ -1427,6 +1435,27 @@ static void hid_gos_cfg_remove(struct hid_device *hdev)
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
||||
static int hid_gos_cfg_reset_resume(struct hid_device *hdev)
|
||||
{
|
||||
u8 os_mode = drvdata.os_mode;
|
||||
int ret;
|
||||
|
||||
ret = mcu_property_out(drvdata.hdev, SET_GAMEPAD_CFG,
|
||||
FEATURE_OS_MODE, &os_mode, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mcu_property_out(drvdata.hdev, GET_GAMEPAD_CFG,
|
||||
FEATURE_OS_MODE, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (drvdata.os_mode != os_mode)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hid_gos_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
@@ -1481,6 +1510,20 @@ static void hid_gos_remove(struct hid_device *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
static int hid_gos_reset_resume(struct hid_device *hdev)
|
||||
{
|
||||
int ep = get_endpoint_address(hdev);
|
||||
|
||||
switch (ep) {
|
||||
case GO_S_CFG_INTF_IN:
|
||||
return hid_gos_cfg_reset_resume(hdev);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id hid_gos_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_QHE,
|
||||
USB_DEVICE_ID_LENOVO_LEGION_GO_S_XINPUT) },
|
||||
@@ -1496,6 +1539,7 @@ static struct hid_driver hid_lenovo_go_s = {
|
||||
.probe = hid_gos_probe,
|
||||
.remove = hid_gos_remove,
|
||||
.raw_event = hid_gos_raw_event,
|
||||
.reset_resume = hid_gos_reset_resume,
|
||||
};
|
||||
module_hid_driver(hid_lenovo_go_s);
|
||||
|
||||
|
||||
@@ -3673,7 +3673,7 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
|
||||
memcpy(&consumer_report[1], &data[3], 4);
|
||||
/* We are called from atomic context */
|
||||
hid_report_raw_event(hidpp->hid_dev, HID_INPUT_REPORT,
|
||||
consumer_report, 5, 1);
|
||||
consumer_report, sizeof(consumer_report), 5, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -4685,6 +4685,44 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
|
||||
{ /* MX Master 4 mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
|
||||
{ /* Logitech Signature K650 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb36f) },
|
||||
{ /* Logitech Signature K650 B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb370) },
|
||||
{ /* Logitech Pebble Keys 2 K380S over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb377) },
|
||||
{ /* Logitech Casa Pop-Up Desk over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb371) },
|
||||
{ /* Logitech Casa Pop-Up Desk B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb374) },
|
||||
{ /* Logitech Wave Keys over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb383) },
|
||||
{ /* Logitech Wave Keys B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb384) },
|
||||
{ /* Logitech Signature Slim K950 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb386) },
|
||||
{ /* Logitech Signature Slim K950 B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb388) },
|
||||
{ /* Logitech MX Keys S over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb378) },
|
||||
{ /* Logitech MX Keys S B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb380) },
|
||||
{ /* Logitech Keys-To-Go 2 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb38c) },
|
||||
{ /* Logitech Pop Icon Keys over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb38f) },
|
||||
{ /* Logitech MX Keys Mini over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb369) },
|
||||
{ /* Logitech MX Keys Mini B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb36e) },
|
||||
{ /* Logitech Signature Slim Solar+ K980 B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb394) },
|
||||
{ /* Logitech Bluetooth Keyboard K250/K251 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb397) },
|
||||
{ /* Logitech Signature Comfort K880 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb39c) },
|
||||
{ /* Logitech Signature Comfort K880 B2B over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb39d) },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -390,6 +390,10 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
struct input_dev *input = msc->input;
|
||||
int x = 0, y = 0, ii, clicks = 0, npoints;
|
||||
|
||||
/* Protect against zero sized recursive calls from DOUBLE_REPORT_ID */
|
||||
if (size < 1)
|
||||
return 0;
|
||||
|
||||
switch (data[0]) {
|
||||
case TRACKPAD_REPORT_ID:
|
||||
case TRACKPAD2_BT_REPORT_ID:
|
||||
@@ -490,6 +494,18 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
/* Sometimes the trackpad sends two touch reports in one
|
||||
* packet.
|
||||
*/
|
||||
|
||||
/* Ensure that we have at least 2 elements (report type and size) */
|
||||
if (size < 2)
|
||||
return 0;
|
||||
|
||||
if (size < data[1] + 2) {
|
||||
hid_warn(hdev,
|
||||
"received report length (%d) was smaller than specified (%d)",
|
||||
size, data[1] + 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
magicmouse_raw_event(hdev, report, data + 2, data[1]);
|
||||
magicmouse_raw_event(hdev, report, data + 2 + data[1],
|
||||
size - 2 - data[1]);
|
||||
|
||||
@@ -128,6 +128,7 @@ struct mcp2221 {
|
||||
u8 *rxbuf;
|
||||
u8 txbuf[64];
|
||||
int rxbuf_idx;
|
||||
int rxbuf_size;
|
||||
int status;
|
||||
u8 cur_i2c_clk_div;
|
||||
struct gpio_chip *gc;
|
||||
@@ -330,12 +331,14 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
|
||||
mcp->txbuf[3] = (u8)(msg->addr << 1);
|
||||
total_len = msg->len;
|
||||
mcp->rxbuf = msg->buf;
|
||||
mcp->rxbuf_size = msg->len;
|
||||
} else {
|
||||
mcp->txbuf[1] = smbus_len;
|
||||
mcp->txbuf[2] = 0;
|
||||
mcp->txbuf[3] = (u8)(smbus_addr << 1);
|
||||
total_len = smbus_len;
|
||||
mcp->rxbuf = smbus_buf;
|
||||
mcp->rxbuf_size = smbus_len;
|
||||
}
|
||||
|
||||
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
|
||||
@@ -919,6 +922,10 @@ static int mcp2221_raw_event(struct hid_device *hdev,
|
||||
mcp->status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (mcp->rxbuf_idx + data[3] > mcp->rxbuf_size) {
|
||||
mcp->status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
buf = mcp->rxbuf;
|
||||
memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
|
||||
mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
|
||||
|
||||
@@ -533,7 +533,7 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
|
||||
}
|
||||
|
||||
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
|
||||
size, 0);
|
||||
size, size, 0);
|
||||
if (ret)
|
||||
dev_warn(&hdev->dev, "failed to report feature\n");
|
||||
}
|
||||
|
||||
@@ -2384,7 +2384,8 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
|
||||
}
|
||||
|
||||
ds4_report = &usb->common;
|
||||
num_touch_reports = usb->num_touch_reports;
|
||||
num_touch_reports = min_t(u8, usb->num_touch_reports,
|
||||
ARRAY_SIZE(usb->touch_reports));
|
||||
touch_reports = usb->touch_reports;
|
||||
} else if (hdev->bus == BUS_BLUETOOTH && report->id == DS4_INPUT_REPORT_BT &&
|
||||
size == DS4_INPUT_REPORT_BT_SIZE) {
|
||||
@@ -2404,7 +2405,8 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
|
||||
}
|
||||
|
||||
ds4_report = &bt->common;
|
||||
num_touch_reports = bt->num_touch_reports;
|
||||
num_touch_reports = min_t(u8, bt->num_touch_reports,
|
||||
ARRAY_SIZE(bt->touch_reports));
|
||||
touch_reports = bt->touch_reports;
|
||||
} else if (hdev->bus == BUS_BLUETOOTH &&
|
||||
report->id == DS4_INPUT_REPORT_BT_MINIMAL &&
|
||||
|
||||
@@ -44,7 +44,7 @@ static int px_raw_event(struct hid_device *hid, struct hid_report *report,
|
||||
data[0] |= (1 << (data[idx] - 0xE0));
|
||||
data[idx] = 0;
|
||||
}
|
||||
hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
|
||||
hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, size, 0);
|
||||
return 1;
|
||||
|
||||
default: /* unknown report */
|
||||
|
||||
@@ -235,7 +235,7 @@ static const struct hid_device_id hid_quirks[] = {
|
||||
* used as a driver. See hid_scan_report().
|
||||
*/
|
||||
static const struct hid_device_id hid_have_special_driver[] = {
|
||||
#if IS_ENABLED(CONFIG_APPLEDISPLAY)
|
||||
#if IS_ENABLED(CONFIG_USB_APPLEDISPLAY)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) },
|
||||
|
||||
@@ -91,17 +91,17 @@ static int sjoyff_init(struct hid_device *hid)
|
||||
|
||||
set_bit(FF_RUMBLE, dev->ffbit);
|
||||
|
||||
error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
|
||||
if (error) {
|
||||
kfree(sjoyff);
|
||||
return error;
|
||||
}
|
||||
|
||||
sjoyff->report = report;
|
||||
sjoyff->report->field[0]->value[0] = 0x01;
|
||||
sjoyff->report->field[0]->value[1] = 0x00;
|
||||
sjoyff->report->field[0]->value[2] = 0x00;
|
||||
hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
|
||||
|
||||
error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
|
||||
if (error) {
|
||||
kfree(sjoyff);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
|
||||
|
||||
@@ -1169,10 +1169,9 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
sixaxis_parse_report(sc, rd, size);
|
||||
} else if ((sc->quirks & MOTION_CONTROLLER_BT) && rd[0] == 0x01 && size == 49) {
|
||||
sixaxis_parse_report(sc, rd, size);
|
||||
} else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 &&
|
||||
size == 49) {
|
||||
} else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 && size == 49) {
|
||||
sixaxis_parse_report(sc, rd, size);
|
||||
} else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) {
|
||||
} else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02 && size >= 12) {
|
||||
nsg_mrxu_parse_report(sc, rd, size);
|
||||
return 1;
|
||||
} else if ((sc->quirks & RB4_GUITAR_PS4_USB) && rd[0] == 0x01 && size == 64) {
|
||||
@@ -1189,7 +1188,7 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
/* Rock Band 3 PS3 Pro instruments set rd[24] to 0xE0 when they're
|
||||
* sending full reports, and 0x02 when only sending navigation.
|
||||
*/
|
||||
if ((sc->quirks & RB3_PRO_INSTRUMENT) && rd[24] == 0x02) {
|
||||
if ((sc->quirks & RB3_PRO_INSTRUMENT) && size >= 25 && rd[24] == 0x02) {
|
||||
/* Only attempt to enable full report every 8 seconds */
|
||||
if (time_after(jiffies, sc->rb3_pro_poke_jiffies)) {
|
||||
sc->rb3_pro_poke_jiffies = jiffies + secs_to_jiffies(8);
|
||||
@@ -1640,9 +1639,6 @@ static int sony_leds_init(struct sony_sc *sc)
|
||||
u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 };
|
||||
u8 use_hw_blink[MAX_LEDS] = { 0 };
|
||||
|
||||
if (WARN_ON(!(sc->quirks & SONY_LED_SUPPORT)))
|
||||
return -EINVAL;
|
||||
|
||||
if (sc->quirks & BUZZ_CONTROLLER) {
|
||||
sc->led_count = 4;
|
||||
use_color_names = 0;
|
||||
@@ -2456,11 +2452,10 @@ static void sony_remove(struct hid_device *hdev)
|
||||
static int sony_suspend(struct hid_device *hdev, pm_message_t message)
|
||||
{
|
||||
#ifdef CONFIG_SONY_FF
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
/* On suspend stop any running force-feedback events */
|
||||
if (SONY_FF_SUPPORT) {
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
if (sc->quirks & SONY_FF_SUPPORT) {
|
||||
sc->left = sc->right = 0;
|
||||
sony_send_output_report(sc);
|
||||
}
|
||||
|
||||
@@ -184,7 +184,9 @@ static int uclogic_input_configured(struct hid_device *hdev,
|
||||
suffix = "System Control";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (suffix) {
|
||||
hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
|
||||
"%s %s", hdev->name, suffix);
|
||||
if (!hi->input->name)
|
||||
|
||||
@@ -85,7 +85,7 @@ void vivaldi_feature_mapping(struct hid_device *hdev,
|
||||
}
|
||||
|
||||
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data,
|
||||
report_len, 0);
|
||||
report_len, report_len, 0);
|
||||
if (ret) {
|
||||
dev_warn(&hdev->dev, "failed to report feature %d\n",
|
||||
field->report->id);
|
||||
|
||||
@@ -149,6 +149,8 @@ static const struct i2c_hid_quirks {
|
||||
I2C_HID_QUIRK_BOGUS_IRQ },
|
||||
{ I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_0D42,
|
||||
I2C_HID_QUIRK_DELAY_WAKEUP_AFTER_RESUME },
|
||||
{ I2C_VENDOR_ID_BLTP, I2C_PRODUCT_ID_BLTP7853,
|
||||
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -574,9 +576,10 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
|
||||
if (ihid->hid->group != HID_GROUP_RMI)
|
||||
pm_wakeup_event(&ihid->client->dev, 0);
|
||||
|
||||
hid_input_report(ihid->hid, HID_INPUT_REPORT,
|
||||
ihid->inbuf + sizeof(__le16),
|
||||
ret_size - sizeof(__le16), 1);
|
||||
hid_safe_input_report(ihid->hid, HID_INPUT_REPORT,
|
||||
ihid->inbuf + sizeof(__le16),
|
||||
ihid->bufsize - sizeof(__le16),
|
||||
ret_size - sizeof(__le16), 1);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -94,7 +94,7 @@ static int quickspi_get_device_descriptor(struct quickspi_device *qsdev)
|
||||
dev_err_once(qsdev->dev, "Read DEVICE_DESCRIPTOR failed, ret = %d\n", ret);
|
||||
dev_err_once(qsdev->dev, "DEVICE_DESCRIPTOR expected len = %u, actual read = %u\n",
|
||||
input_len, read_len);
|
||||
return ret;
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
input_rep_type = ((struct input_report_body_header *)read_buf)->input_report_type;
|
||||
@@ -318,7 +318,7 @@ int reset_tic(struct quickspi_device *qsdev)
|
||||
dev_err_once(qsdev->dev, "Read RESET_RESPONSE body failed, ret = %d\n", ret);
|
||||
dev_err_once(qsdev->dev, "RESET_RESPONSE body expected len = %u, actual = %u\n",
|
||||
read_len, actual_read_len);
|
||||
return ret;
|
||||
return ret ?: -EINVAL;
|
||||
}
|
||||
|
||||
input_rep_type = FIELD_GET(HIDSPI_IN_REP_BDY_HDR_REP_TYPE, reset_response);
|
||||
|
||||
@@ -283,9 +283,9 @@ static void hid_irq_in(struct urb *urb)
|
||||
break;
|
||||
usbhid_mark_busy(usbhid);
|
||||
if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
|
||||
hid_input_report(urb->context, HID_INPUT_REPORT,
|
||||
urb->transfer_buffer,
|
||||
urb->actual_length, 1);
|
||||
hid_safe_input_report(urb->context, HID_INPUT_REPORT,
|
||||
urb->transfer_buffer, urb->transfer_buffer_length,
|
||||
urb->actual_length, 1);
|
||||
/*
|
||||
* autosuspend refused while keys are pressed
|
||||
* because most keyboards don't wake up when
|
||||
@@ -482,9 +482,10 @@ static void hid_ctrl(struct urb *urb)
|
||||
switch (status) {
|
||||
case 0: /* success */
|
||||
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
|
||||
hid_input_report(urb->context,
|
||||
hid_safe_input_report(urb->context,
|
||||
usbhid->ctrl[usbhid->ctrltail].report->type,
|
||||
urb->transfer_buffer, urb->actual_length, 0);
|
||||
urb->transfer_buffer, urb->transfer_buffer_length,
|
||||
urb->actual_length, 0);
|
||||
break;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
unplug = 1;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "hid-pidff.h"
|
||||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stringify.h>
|
||||
@@ -326,8 +327,10 @@ static s32 pidff_clamp(s32 i, struct hid_field *field)
|
||||
*/
|
||||
static int pidff_rescale(int i, int max, struct hid_field *field)
|
||||
{
|
||||
return i * (field->logical_maximum - field->logical_minimum) / max +
|
||||
field->logical_minimum;
|
||||
/* 64 bits needed for big values during rescale */
|
||||
s64 result = field->logical_maximum - field->logical_minimum;
|
||||
|
||||
return div_s64(result * i, max) + field->logical_minimum;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -90,7 +90,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
|
||||
kfree(buf);
|
||||
continue;
|
||||
}
|
||||
err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false);
|
||||
err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, size, false);
|
||||
if (err) {
|
||||
hid_warn(hdev, "%s: unable to flush event due to error %d\n",
|
||||
__func__, err);
|
||||
@@ -334,7 +334,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
||||
data, n, WAC_CMD_RETRIES);
|
||||
if (ret == n && features->type == HID_GENERIC) {
|
||||
ret = hid_report_raw_event(hdev,
|
||||
HID_FEATURE_REPORT, data, n, 0);
|
||||
HID_FEATURE_REPORT, data, n, n, 0);
|
||||
} else if (ret == 2 && features->type != HID_GENERIC) {
|
||||
features->touch_max = data[1];
|
||||
} else {
|
||||
@@ -395,7 +395,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
||||
data, n, WAC_CMD_RETRIES);
|
||||
if (ret == n) {
|
||||
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
|
||||
data, n, 0);
|
||||
data, n, n, 0);
|
||||
} else {
|
||||
hid_warn(hdev, "%s: could not retrieve sensor offsets\n",
|
||||
__func__);
|
||||
|
||||
@@ -201,7 +201,7 @@ static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report)
|
||||
* we just need to setup the input fields, so using
|
||||
* hid_report_raw_event is safe.
|
||||
*/
|
||||
hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, size, 1);
|
||||
hid_report_raw_event(ghid->hid, report->type, ghid->inbuf, ghid->bufsize, size, 1);
|
||||
}
|
||||
|
||||
static void gb_hid_init_reports(struct gb_hid *ghid)
|
||||
|
||||
@@ -1030,6 +1030,8 @@ struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_ty
|
||||
int hid_set_field(struct hid_field *, unsigned, __s32);
|
||||
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt);
|
||||
int hid_safe_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data,
|
||||
size_t bufsize, u32 size, int interrupt);
|
||||
struct hid_field *hidinput_get_led_field(struct hid_device *hid);
|
||||
unsigned int hidinput_count_leds(struct hid_device *hid);
|
||||
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
|
||||
@@ -1298,8 +1300,8 @@ static inline u32 hid_report_len(struct hid_report *report)
|
||||
return DIV_ROUND_UP(report->size, 8) + (report->id > 0);
|
||||
}
|
||||
|
||||
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt);
|
||||
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
|
||||
size_t bufsize, u32 size, int interrupt);
|
||||
|
||||
/* HID quirks API */
|
||||
unsigned long hid_lookup_quirk(const struct hid_device *hdev);
|
||||
|
||||
@@ -72,8 +72,8 @@ struct hid_ops {
|
||||
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
|
||||
u64 source, bool from_bpf);
|
||||
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
|
||||
u8 *data, u32 size, int interrupt, u64 source, bool from_bpf,
|
||||
bool lock_already_taken);
|
||||
u8 *data, size_t bufsize, u32 size, int interrupt, u64 source,
|
||||
bool from_bpf, bool lock_already_taken);
|
||||
struct module *owner;
|
||||
const struct bus_type *bus_type;
|
||||
};
|
||||
@@ -200,7 +200,8 @@ struct hid_bpf {
|
||||
|
||||
#ifdef CONFIG_HID_BPF
|
||||
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
|
||||
u32 *size, int interrupt, u64 source, bool from_bpf);
|
||||
size_t *buf_size, u32 *size, int interrupt, u64 source,
|
||||
bool from_bpf);
|
||||
int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
u32 size, enum hid_report_type rtype,
|
||||
@@ -215,8 +216,11 @@ int hid_bpf_device_init(struct hid_device *hid);
|
||||
const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size);
|
||||
#else /* CONFIG_HID_BPF */
|
||||
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
|
||||
u8 *data, u32 *size, int interrupt,
|
||||
u64 source, bool from_bpf) { return data; }
|
||||
u8 *data, size_t *buf_size, u32 *size,
|
||||
int interrupt, u64 source, bool from_bpf)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
|
||||
unsigned char reportnum, u8 *buf,
|
||||
u32 size, enum hid_report_type rtype,
|
||||
|
||||
Reference in New Issue
Block a user