[PATCH] HID: roccat: pass data size to roccat_report_event()
From: Dmitry Antipov <hidden>
Date: 2026-09-15 08:53:19
Subsystem:
hid core layer, roccat drivers, the rest · Maintainers:
Jiri Kosina, Benjamin Tissoires, Stefan Achatz, Linus Torvalds
Adjust roccat_report_event() to take both report and report size.
The goal is to make roccat_report_event() lockfree. Since callers
are likely to pass stack-allocated event, it should be copied,
which requires to know event size. This size is recorded in
'report_size' of 'struct roccat_device', but taking the device
pointer is racy without taking global 'devices_lock', and taking
the latter from atomic context (from where roccat_report_event()
may be called) is definitely wrong.
Signed-off-by: Dmitry Antipov <redacted>
---
With this patch, roccat_report_event() may be implemented as follows:
struct roccat_event {
struct work_struct work;
int minor;
u8 data[];
};
static void roccat_event_handler(struct work_struct *work)
{
struct roccat_event *event;
event = container_of(work, struct roccat_event, work);
/* In this context, locking is safe. Get the device
pointer using event->minor and, if the device
is still present, do the rest of event reporting. */
}
int roccat_report_event(int minor, u8 const *data, int size)
{
struct roccat_event *event;
event = kzalloc_flex(*event, data, size, GFP_ATOMIC);
if (!event)
return -ENOMEM;
INIT_WORK(&event->work, roccat_event_handler);
memcpy(event->data, data, size);
event->minor = minor;
queue_work([likely dedicated single-threaded workqueue], &event->work);
return 0;
}
---
drivers/hid/hid-roccat-arvo.c | 3 ++-
drivers/hid/hid-roccat-isku.c | 7 +++++--
drivers/hid/hid-roccat-kone.c | 10 +++++++---
drivers/hid/hid-roccat-koneplus.c | 6 ++++--
drivers/hid/hid-roccat-konepure.c | 2 +-
drivers/hid/hid-roccat-kovaplus.c | 6 ++++--
drivers/hid/hid-roccat-pyra.c | 9 ++++++---
drivers/hid/hid-roccat-ryos.c | 2 +-
drivers/hid/hid-roccat-savu.c | 3 ++-
drivers/hid/hid-roccat.c | 3 ++-
include/linux/hid-roccat.h | 2 +-
11 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 0cf2f0008c7f..2a4e42ad4aae 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c@@ -400,7 +400,8 @@ static void arvo_report_to_chrdev(struct arvo_device const *arvo, roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_RELEASE; roccat_report_event(arvo->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } static int arvo_raw_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index 93a49c93ae8c..abda7551dd1f 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c@@ -98,7 +98,9 @@ static ssize_t isku_sysfs_set_actual_profile(struct device *dev, roccat_report.data1 = profile + 1; roccat_report.data2 = 0; roccat_report.profile = profile + 1; - roccat_report_event(isku->chrdev_minor, (uint8_t const *)&roccat_report); + roccat_report_event(isku->chrdev_minor, + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); mutex_unlock(&isku->isku_lock);
@@ -395,7 +397,8 @@ static void isku_report_to_chrdev(struct isku_device const *isku, roccat_report.data2 = button_report->data2; roccat_report.profile = isku->actual_profile + 1; roccat_report_event(isku->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } static int isku_raw_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 3dae9eaa0b6f..38bed3cdd592 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c@@ -49,7 +49,9 @@ static void kone_profile_report(struct kone_device *kone, uint new_profile) roccat_report.event = kone_mouse_event_switch_profile; roccat_report.value = new_profile; roccat_report.key = 0; - roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report); + roccat_report_event(kone->chrdev_minor, + (uint8_t *)&roccat_report, + sizeof(roccat_report)); } static int kone_receive(struct usb_device *usb_dev, uint usb_command,
@@ -824,7 +826,8 @@ static void kone_report_to_chrdev(struct kone_device const *kone, roccat_report.value = event->value; roccat_report.key = 0; roccat_report_event(kone->chrdev_minor, - (uint8_t *)&roccat_report); + (uint8_t *)&roccat_report, + sizeof(roccat_report)); break; case kone_mouse_event_call_overlong_macro: case kone_mouse_event_multimedia:
@@ -833,7 +836,8 @@ static void kone_report_to_chrdev(struct kone_device const *kone, roccat_report.value = kone->actual_profile; roccat_report.key = event->macro_key; roccat_report_event(kone->chrdev_minor, - (uint8_t *)&roccat_report); + (uint8_t *)&roccat_report, + sizeof(roccat_report)); } break; }
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index f80a60539a96..77cb88957f8b 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c@@ -280,7 +280,8 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, roccat_report.data2 = 0; roccat_report.profile = profile + 1; roccat_report_event(koneplus->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); mutex_unlock(&koneplus->koneplus_lock);
@@ -507,7 +508,8 @@ static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus, roccat_report.data2 = button_report->data2; roccat_report.profile = koneplus->actual_profile + 1; roccat_report_event(koneplus->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } static int koneplus_raw_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
index 7f753dfc2a10..bed5e1e8a49e 100644
--- a/drivers/hid/hid-roccat-konepure.c
+++ b/drivers/hid/hid-roccat-konepure.c@@ -185,7 +185,7 @@ static int konepure_raw_event(struct hid_device *hdev, return 0; if (konepure != NULL && konepure->roccat_claimed) - roccat_report_event(konepure->chrdev_minor, data); + roccat_report_event(konepure->chrdev_minor, data, size); return 0; }
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index 9ec42c218ef9..277a32313f45 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c@@ -310,7 +310,8 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, roccat_report.data1 = profile + 1; roccat_report.data2 = 0; roccat_report_event(kovaplus->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); mutex_unlock(&kovaplus->kovaplus_lock);
@@ -598,7 +599,8 @@ static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus, roccat_report.data2 = button_report->data2; roccat_report_event(kovaplus->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } static int kovaplus_raw_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 0d515995bb9d..eb1dcdc17c29 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c@@ -266,7 +266,8 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, roccat_report.value = settings->startup_profile + 1; roccat_report.key = 0; roccat_report_event(pyra->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); mutex_unlock(&pyra->pyra_lock); return PYRA_SIZE_SETTINGS;
@@ -524,7 +525,8 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra, roccat_report.value = button_event->data1; roccat_report.key = 0; roccat_report_event(pyra->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); break; case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO: case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
@@ -538,7 +540,8 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra, */ roccat_report.value = pyra->actual_profile + 1; roccat_report_event(pyra->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } break; }
diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c
index db83f42457da..6267dd49acc8 100644
--- a/drivers/hid/hid-roccat-ryos.c
+++ b/drivers/hid/hid-roccat-ryos.c@@ -193,7 +193,7 @@ static int ryos_raw_event(struct hid_device *hdev, return 0; if (ryos != NULL && ryos->roccat_claimed) - roccat_report_event(ryos->chrdev_minor, data); + roccat_report_event(ryos->chrdev_minor, data, size); return 0; }
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
index 679136933560..b3b812a1a38b 100644
--- a/drivers/hid/hid-roccat-savu.c
+++ b/drivers/hid/hid-roccat-savu.c@@ -166,7 +166,8 @@ static void savu_report_to_chrdev(struct roccat_common2_device const *savu, roccat_report.data[0] = special_report->data[0]; roccat_report.data[1] = special_report->data[1]; roccat_report_event(savu->chrdev_minor, - (uint8_t const *)&roccat_report); + (uint8_t const *)&roccat_report, + sizeof(roccat_report)); } static int savu_raw_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index 4f15eb951039..ca09820ee5d3 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c@@ -248,12 +248,13 @@ static int roccat_release(struct inode *inode, struct file *file) * roccat_report_event() - output data to readers * @minor: minor device number returned by roccat_connect() * @data: pointer to data + * @size: data size (expected to be equal to device->report_size) * * Return value is zero on success, a negative error code on failure. * * This is called from interrupt handler. */ -int roccat_report_event(int minor, u8 const *data) +int roccat_report_event(int minor, u8 const *data, int size) { struct roccat_device *device; struct roccat_reader *reader;
diff --git a/include/linux/hid-roccat.h b/include/linux/hid-roccat.h
index 753654fff07f..2be48e3d92a9 100644
--- a/include/linux/hid-roccat.h
+++ b/include/linux/hid-roccat.h@@ -19,7 +19,7 @@ int roccat_connect(const struct class *klass, struct hid_device *hid, int report_size); void roccat_disconnect(int minor); -int roccat_report_event(int minor, u8 const *data); +int roccat_report_event(int minor, u8 const *data, int size); #endif
--
2.55.0