[lvc-project] [PATCH] HID: roccat: pass data size to roccat_report_event()

Dmitry Antipov dmantipov at yandex.ru
Tue Sep 15 11:53:11 MSK 2026


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 <dmantipov at yandex.ru>
---
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




More information about the lvc-project mailing list