* [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private
@ 2026-10-14 5:13 Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 1/5] HID: core: Move internal declarations and drop unused exports Dmitry Torokhov
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
This series cleans up internal HID core and hidraw header boundaries.
First, internal HID core declarations and unused symbol exports are
moved out of include/linux/hid.h into a private drivers/hid/hid-core.h
header. Next, a hidraw_instance() accessor is introduced in
include/linux/hidraw.h so HID drivers that only need the hidraw minor
number for naming or debug logging no longer dereference struct hidraw
directly. After converting the drivers and dropping unused
linux/hidraw.h includes, hidraw.h is moved to drivers/hid/hidraw.h and
struct hidraw along with its internal buffer and list structures are
made private to drivers/hid/hidraw.c.
Dmitry Torokhov (5):
HID: core: Move internal declarations and drop unused exports
HID: hidraw: Introduce hidraw_instance() helper
HID: Use hidraw_instance() in drivers
HID: Drop unused linux/hidraw.h includes
HID: hidraw: Make hidraw.h private to HID subsystem
drivers/hid/Kconfig | 3 ++
drivers/hid/hid-core.c | 7 ++--
drivers/hid/hid-core.h | 20 +++++++++++
drivers/hid/hid-cp2112.c | 15 ++++----
drivers/hid/hid-ft260.c | 2 +-
drivers/hid/hid-input.c | 4 +--
drivers/hid/hid-led.c | 10 ++++--
drivers/hid/hid-mcp2200.c | 1 -
drivers/hid/hid-mcp2221.c | 1 -
drivers/hid/hid-quirks.c | 1 +
drivers/hid/hid-u2fzero.c | 10 ++++--
drivers/hid/hid-winwing.c | 1 -
drivers/hid/hidraw.c | 48 ++++++++++++++++++++++---
{include/linux => drivers/hid}/hidraw.h | 32 +++--------------
drivers/hid/usbhid/hid-core.c | 1 -
include/linux/hid.h | 8 -----
net/bluetooth/hidp/core.c | 1 -
17 files changed, 100 insertions(+), 65 deletions(-)
create mode 100644 drivers/hid/hid-core.h
rename {include/linux => drivers/hid}/hidraw.h (58%)
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/5] HID: core: Move internal declarations and drop unused exports
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
@ 2026-10-14 5:13 ` Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 2/5] HID: hidraw: Introduce hidraw_instance() helper Dmitry Torokhov
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
Several declarations in the public HID header and exported symbols are
used solely within the core HID module (linked together from hid-core,
hid-input, and hid-quirks into hid.o).
Move internal request, input hook, resolution multiplier, and device
matching declarations into a private header shared across core HID
sources, and drop the unused GPL symbol exports.
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 3 +--
drivers/hid/hid-core.h | 20 ++++++++++++++++++++
drivers/hid/hid-input.c | 4 +---
drivers/hid/hid-quirks.c | 1 +
include/linux/hid.h | 8 --------
5 files changed, 23 insertions(+), 13 deletions(-)
create mode 100644 drivers/hid/hid-core.h
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index cf123347a2af..ec44d99fd416 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -33,6 +33,7 @@
#include <linux/hid-debug.h>
#include <linux/hidraw.h>
+#include "hid-core.h"
#include "hid-ids.h"
/*
@@ -1243,7 +1244,6 @@ void hid_setup_resolution_multiplier(struct hid_device *hid)
}
}
}
-EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
static int hid_parse_collections(struct hid_device *device)
{
@@ -2031,7 +2031,6 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
return 0;
}
-EXPORT_SYMBOL_GPL(__hid_request);
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
size_t bufsize, u32 size, int interrupt)
diff --git a/drivers/hid/hid-core.h b/drivers/hid/hid-core.h
new file mode 100644
index 000000000000..f20028d499fe
--- /dev/null
+++ b/drivers/hid/hid-core.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __HID_CORE_H
+#define __HID_CORE_H
+
+#include <linux/hid.h>
+
+int __hid_request(struct hid_device *hid, struct hid_report *report,
+ enum hid_class_request reqtype);
+
+int hidinput_connect(struct hid_device *hid, unsigned int force);
+void hidinput_disconnect(struct hid_device *hid);
+void hidinput_hid_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value);
+void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
+
+void hid_setup_resolution_multiplier(struct hid_device *hid);
+bool hid_match_one_id(const struct hid_device *hdev,
+ const struct hid_device_id *id);
+
+#endif /* __HID_CORE_H */
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 3487600cadb4..770087c4cf5d 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -20,6 +20,7 @@
#include <linux/hid.h>
#include <linux/hid-debug.h>
+#include "hid-core.h"
#include "hid-ids.h"
#define unk KEY_UNKNOWN
@@ -1793,7 +1794,6 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
list_for_each_entry(hidinput, &hid->inputs, list)
input_sync(hidinput->input);
}
-EXPORT_SYMBOL_GPL(hidinput_report_event);
static int hidinput_find_field(struct hid_device *hid, unsigned int type,
unsigned int code, struct hid_field **field)
@@ -2418,7 +2418,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return -1;
}
-EXPORT_SYMBOL_GPL(hidinput_connect);
void hidinput_disconnect(struct hid_device *hid)
{
@@ -2440,7 +2439,6 @@ void hidinput_disconnect(struct hid_device *hid)
* synchronously and are safe. */
cancel_work_sync(&hid->led_work);
}
-EXPORT_SYMBOL_GPL(hidinput_disconnect);
void hidinput_reset_resume(struct hid_device *hid)
{
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 57d8efdd9b89..db5dda650ed3 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -18,6 +18,7 @@
#include <linux/mutex.h>
#include <linux/input/elan-i2c-ids.h>
+#include "hid-core.h"
#include "hid-ids.h"
/*
diff --git a/include/linux/hid.h b/include/linux/hid.h
index b240baa95ab5..b956ae6b753c 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1019,10 +1019,6 @@ extern void hid_unregister_driver(struct hid_driver *);
module_driver(__hid_driver, hid_register_driver, \
hid_unregister_driver)
-extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *hid, unsigned int force);
-extern void hidinput_disconnect(struct hid_device *);
void hidinput_reset_resume(struct hid_device *hid);
struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
@@ -1036,7 +1032,6 @@ 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);
void hid_output_report(struct hid_report *report, __u8 *data);
-int __hid_request(struct hid_device *hid, struct hid_report *rep, enum hid_class_request reqtype);
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device,
@@ -1048,13 +1043,10 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int field_index,
unsigned int report_counts);
-void hid_setup_resolution_multiplier(struct hid_device *hid);
int hid_open_report(struct hid_device *device);
int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
void hid_disconnect(struct hid_device *hid);
-bool hid_match_one_id(const struct hid_device *hdev,
- const struct hid_device_id *id);
const struct hid_device_id *hid_match_id(const struct hid_device *hdev,
const struct hid_device_id *id);
const struct hid_device_id *hid_match_device(struct hid_device *hdev,
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/5] HID: hidraw: Introduce hidraw_instance() helper
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 1/5] HID: core: Move internal declarations and drop unused exports Dmitry Torokhov
@ 2026-10-14 5:13 ` Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 3/5] HID: Use hidraw_instance() in drivers Dmitry Torokhov
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
Several drivers and subsystem helpers need to determine the minor number
of the hidraw node associated with an underlying HID device. Currently
they access internal driver data and cast the hidraw pointer directly,
requiring drivers to include the internal hidraw header.
Introduce hidraw_instance() to validate that the device was claimed by
hidraw and return its minor node number, or -ENODEV if hidraw is not
connected or hidraw support is disabled. Also use the new helper in
hid_connect().
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 2 +-
drivers/hid/hidraw.c | 15 +++++++++++++++
include/linux/hidraw.h | 3 +++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ec44d99fd416..c430f2d0d779 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2346,7 +2346,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
((struct hiddev *)hdev->hiddev)->minor);
if (hdev->claimed & HID_CLAIMED_HIDRAW)
len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
- ((struct hidraw *)hdev->hidraw)->minor);
+ hidraw_instance(hdev));
type = "Device";
for (i = 0; i < hdev->maxcollection; i++) {
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 9129fabed181..949e7546339f 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -665,6 +665,21 @@ void hidraw_disconnect(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hidraw_disconnect);
+/**
+ * hidraw_instance - get hidraw instance minor number for a HID device
+ * @hdev: HID device
+ *
+ * Return: minor number of the hidraw node, or -ENODEV if not connected
+ */
+int hidraw_instance(const struct hid_device *hdev)
+{
+ if ((hdev->claimed & HID_CLAIMED_HIDRAW) && hdev->hidraw)
+ return ((struct hidraw *)hdev->hidraw)->minor;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(hidraw_instance);
+
int __init hidraw_init(void)
{
int result;
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
index 18fd30a288de..3021454ba513 100644
--- a/include/linux/hidraw.h
+++ b/include/linux/hidraw.h
@@ -5,6 +5,7 @@
#ifndef _HIDRAW_H
#define _HIDRAW_H
+#include <linux/errno.h>
#include <uapi/linux/hidraw.h>
@@ -41,12 +42,14 @@ void hidraw_exit(void);
int hidraw_report_event(struct hid_device *, u8 *, int);
int hidraw_connect(struct hid_device *);
void hidraw_disconnect(struct hid_device *);
+int hidraw_instance(const struct hid_device *hdev);
#else
static inline int hidraw_init(void) { return 0; }
static inline void hidraw_exit(void) { }
static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
static inline int hidraw_connect(struct hid_device *hid) { return -1; }
static inline void hidraw_disconnect(struct hid_device *hid) { }
+static inline int hidraw_instance(const struct hid_device *hdev) { return -ENODEV; }
#endif
#endif
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/5] HID: Use hidraw_instance() in drivers
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 1/5] HID: core: Move internal declarations and drop unused exports Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 2/5] HID: hidraw: Introduce hidraw_instance() helper Dmitry Torokhov
@ 2026-10-14 5:13 ` Dmitry Torokhov
2026-10-14 10:38 ` [PATCH] HID: cp2112: don't dereference hdev->hidraw unconditionally Jinmo Yang
2026-10-14 5:13 ` [PATCH 4/5] HID: Drop unused linux/hidraw.h includes Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 5/5] HID: hidraw: Make hidraw.h private to HID subsystem Dmitry Torokhov
4 siblings, 1 reply; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
Instead of directly dereferencing struct hidraw to inspect minor device
numbers, use hidraw_instance(). This removes the dependency of these
drivers on the internal struct hidraw layout.
For hid-cp2112, fall back to dev_name() when hidraw is not available.
For hid-led and hid-u2fzero, require CONFIG_HIDRAW and propagate errors
if hidraw is unavailable.
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/Kconfig | 3 +++
drivers/hid/hid-cp2112.c | 13 ++++++++-----
drivers/hid/hid-led.c | 8 ++++++--
drivers/hid/hid-u2fzero.c | 8 ++++++--
4 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index f9bcaeb66385..1d2657edab27 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -587,6 +587,7 @@ config HID_LCPOWER
config HID_LED
tristate "Simple RGB LED support"
+ depends on HIDRAW
depends on LEDS_CLASS
help
Support for simple RGB LED devices. Currently supported are:
@@ -1252,6 +1253,7 @@ config HID_TOPRE
config HID_THINGM
tristate "ThingM blink(1) USB RGB LED"
+ depends on HIDRAW
depends on LEDS_CLASS
select HID_LED
help
@@ -1285,6 +1287,7 @@ config HID_UDRAW_PS3
config HID_U2FZERO
tristate "U2F Zero LED and RNG support"
depends on USB_HID
+ depends on HIDRAW
depends on LEDS_CLASS
depends on HW_RANDOM
help
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 04379db93571..148946b04bff 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -1225,7 +1225,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct gpio_irq_chip *girq;
struct i2c_timings timings;
u32 addr;
- int ret;
+ int ret, instance;
dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -1330,9 +1330,13 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.algo = &smbus_algorithm;
dev->adap.algo_data = dev;
dev->adap.dev.parent = &hdev->dev;
- snprintf(dev->adap.name, sizeof(dev->adap.name),
- "CP2112 SMBus Bridge on hidraw%d",
- ((struct hidraw *)hdev->hidraw)->minor);
+ instance = hidraw_instance(hdev);
+ if (instance >= 0)
+ snprintf(dev->adap.name, sizeof(dev->adap.name),
+ "CP2112 SMBus Bridge on hidraw%d", instance);
+ else
+ snprintf(dev->adap.name, sizeof(dev->adap.name),
+ "CP2112 SMBus Bridge on %s", dev_name(&hdev->dev));
dev->hwversion = buf[2];
init_waitqueue_head(&dev->wait);
@@ -1494,4 +1498,3 @@ module_hid_driver(cp2112_driver);
MODULE_DESCRIPTION("Silicon Labs HID USB to SMBus master bridge");
MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c
index 7d82f8d426bb..63fd723d9e69 100644
--- a/drivers/hid/hid-led.c
+++ b/drivers/hid/hid-led.c
@@ -448,7 +448,7 @@ static int hidled_init_rgb(struct hidled_rgb *rgb, unsigned int minor)
static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct hidled_device *ldev;
- unsigned int minor;
+ int minor;
int ret, i;
ldev = devm_kzalloc(&hdev->dev, sizeof(*ldev), GFP_KERNEL);
@@ -488,7 +488,11 @@ static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
return ret;
- minor = ((struct hidraw *) hdev->hidraw)->minor;
+ minor = hidraw_instance(hdev);
+ if (minor < 0) {
+ hid_hw_stop(hdev);
+ return minor;
+ }
for (i = 0; i < ldev->config->num_leds; i++) {
ldev->rgb[i].ldev = ldev;
diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c
index 82404b6e2d25..83e223c12cd6 100644
--- a/drivers/hid/hid-u2fzero.c
+++ b/drivers/hid/hid-u2fzero.c
@@ -307,7 +307,7 @@ static int u2fzero_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct u2fzero_device *dev;
- unsigned int minor;
+ int minor;
int ret;
if (!hid_is_usb(hdev))
@@ -347,7 +347,11 @@ static int u2fzero_probe(struct hid_device *hdev,
dev->present = true;
- minor = ((struct hidraw *) hdev->hidraw)->minor;
+ minor = hidraw_instance(hdev);
+ if (minor < 0) {
+ ret = minor;
+ goto err_free_urb;
+ }
ret = u2fzero_init_led(dev, minor);
if (ret)
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/5] HID: Drop unused linux/hidraw.h includes
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
` (2 preceding siblings ...)
2026-10-14 5:13 ` [PATCH 3/5] HID: Use hidraw_instance() in drivers Dmitry Torokhov
@ 2026-10-14 5:13 ` Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 5/5] HID: hidraw: Make hidraw.h private to HID subsystem Dmitry Torokhov
4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
Several HID transport and sub-drivers include linux/hidraw.h without
referencing any definitions from it. Drop these unnecessary includes.
In hid-ft260, replace the hidraw.h include with linux/hid.h directly to
preserve the declarations it previously relied on indirectly.
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-ft260.c | 2 +-
drivers/hid/hid-mcp2200.c | 1 -
drivers/hid/hid-mcp2221.c | 1 -
drivers/hid/hid-winwing.c | 1 -
drivers/hid/usbhid/hid-core.c | 1 -
net/bluetooth/hidp/core.c | 1 -
6 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
index 70e2eedb465a..c4d13a6a575d 100644
--- a/drivers/hid/hid-ft260.c
+++ b/drivers/hid/hid-ft260.c
@@ -9,7 +9,7 @@
*/
#include "hid-ids.h"
-#include <linux/hidraw.h>
+#include <linux/hid.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/usb.h>
diff --git a/drivers/hid/hid-mcp2200.c b/drivers/hid/hid-mcp2200.c
index dafdd5b4a079..9c82de069b8b 100644
--- a/drivers/hid/hid-mcp2200.c
+++ b/drivers/hid/hid-mcp2200.c
@@ -12,7 +12,6 @@
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include "hid-ids.h"
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index e4ddd8e9293b..bd6b92b5a09d 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -14,7 +14,6 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/iio/iio.h>
diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c
index 9cd25a77999e..5223baf2d020 100644
--- a/drivers/hid/hid-winwing.c
+++ b/drivers/hid/hid-winwing.c
@@ -8,7 +8,6 @@
#include <linux/device.h>
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 96b0181cf819..e398afce73fc 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -34,7 +34,6 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
-#include <linux/hidraw.h>
#include "usbhid.h"
#include "hid-pidff.h"
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 0e24c5e2955e..bb408599a28b 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/file.h>
#include <linux/kthread.h>
-#include <linux/hidraw.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 5/5] HID: hidraw: Make hidraw.h private to HID subsystem
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
` (3 preceding siblings ...)
2026-10-14 5:13 ` [PATCH 4/5] HID: Drop unused linux/hidraw.h includes Dmitry Torokhov
@ 2026-10-14 5:13 ` Dmitry Torokhov
4 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2026-10-14 5:13 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Michael Zaidman,
Rishi Gupta, Heiner Kallweit, David Barksdale, Andrej Shadura,
Johannes Roith, linux-input, linux-bluetooth, linux-kernel
With all external consumers converted to use the hidraw instance helper,
hidraw.h no longer needs to be exposed in include/linux.
Move the header into drivers/hid, keep private buffer and list
structures internal to hidraw.c, and drop unneeded symbol exports
since hidraw and hid-core are built into the same module.
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 2 +-
drivers/hid/hid-cp2112.c | 2 +-
drivers/hid/hid-led.c | 2 +-
drivers/hid/hid-u2fzero.c | 2 +-
drivers/hid/hidraw.c | 33 ++++++++++++++++++++++---
{include/linux => drivers/hid}/hidraw.h | 29 +---------------------
6 files changed, 34 insertions(+), 36 deletions(-)
rename {include/linux => drivers/hid}/hidraw.h (63%)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c430f2d0d779..a5d03504c061 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -31,10 +31,10 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
-#include <linux/hidraw.h>
#include "hid-core.h"
#include "hid-ids.h"
+#include "hidraw.h"
/*
* Version Information
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 148946b04bff..0f65ce44e677 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -20,7 +20,6 @@
#include <linux/cleanup.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -28,6 +27,7 @@
#include <linux/string_choices.h>
#include <linux/usb/ch9.h>
#include "hid-ids.h"
+#include "hidraw.h"
/**
* enum cp2112_child_acpi_cell_addrs - Child ACPI addresses for CP2112 sub-functions
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c
index 63fd723d9e69..f5a798c7979e 100644
--- a/drivers/hid/hid-led.c
+++ b/drivers/hid/hid-led.c
@@ -8,12 +8,12 @@
*/
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include "hid-ids.h"
+#include "hidraw.h"
enum hidled_report_type {
RAW_REQUEST,
diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c
index 83e223c12cd6..4b9271b4e45e 100644
--- a/drivers/hid/hid-u2fzero.c
+++ b/drivers/hid/hid-u2fzero.c
@@ -12,7 +12,6 @@
*/
#include <linux/hid.h>
-#include <linux/hidraw.h>
#include <linux/hw_random.h>
#include <linux/leds.h>
#include <linux/module.h>
@@ -21,6 +20,7 @@
#include "usbhid/usbhid.h"
#include "hid-ids.h"
+#include "hidraw.h"
#define DRIVER_SHORT "u2fzero"
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 949e7546339f..9d0df711ed5d 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -27,8 +27,36 @@
#include <linux/mutex.h>
#include <linux/sched/signal.h>
#include <linux/string.h>
+#include <uapi/linux/hidraw.h>
+
+#include "hidraw.h"
+
+struct hidraw {
+ unsigned int minor;
+ int exist;
+ int open;
+ wait_queue_head_t wait;
+ struct hid_device *hid;
+ struct device *dev;
+ spinlock_t list_lock;
+ struct list_head list;
+};
+
+struct hidraw_report {
+ __u8 *value;
+ int len;
+};
-#include <linux/hidraw.h>
+struct hidraw_list {
+ struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];
+ int head;
+ int tail;
+ struct fasync_struct *fasync;
+ struct hidraw *hidraw;
+ struct list_head node;
+ struct mutex read_mutex;
+ bool revoked;
+};
static int hidraw_major;
static struct cdev hidraw_cdev;
@@ -594,7 +622,6 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
wake_up_interruptible(&dev->wait);
return ret;
}
-EXPORT_SYMBOL_GPL(hidraw_report_event);
int hidraw_connect(struct hid_device *hid)
{
@@ -651,7 +678,6 @@ int hidraw_connect(struct hid_device *hid)
return result;
}
-EXPORT_SYMBOL_GPL(hidraw_connect);
void hidraw_disconnect(struct hid_device *hid)
{
@@ -663,7 +689,6 @@ void hidraw_disconnect(struct hid_device *hid)
up_write(&minors_rwsem);
}
-EXPORT_SYMBOL_GPL(hidraw_disconnect);
/**
* hidraw_instance - get hidraw instance minor number for a HID device
diff --git a/include/linux/hidraw.h b/drivers/hid/hidraw.h
similarity index 63%
rename from include/linux/hidraw.h
rename to drivers/hid/hidraw.h
index 3021454ba513..a822007ce5f8 100644
--- a/include/linux/hidraw.h
+++ b/drivers/hid/hidraw.h
@@ -6,35 +6,8 @@
#define _HIDRAW_H
#include <linux/errno.h>
-#include <uapi/linux/hidraw.h>
-
-struct hidraw {
- unsigned int minor;
- int exist;
- int open;
- wait_queue_head_t wait;
- struct hid_device *hid;
- struct device *dev;
- spinlock_t list_lock;
- struct list_head list;
-};
-
-struct hidraw_report {
- __u8 *value;
- int len;
-};
-
-struct hidraw_list {
- struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];
- int head;
- int tail;
- struct fasync_struct *fasync;
- struct hidraw *hidraw;
- struct list_head node;
- struct mutex read_mutex;
- bool revoked;
-};
+struct hid_device;
#ifdef CONFIG_HIDRAW
int hidraw_init(void);
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH] HID: cp2112: don't dereference hdev->hidraw unconditionally
2026-10-14 5:13 ` [PATCH 3/5] HID: Use hidraw_instance() in drivers Dmitry Torokhov
@ 2026-10-14 10:38 ` Jinmo Yang
2026-10-14 13:50 ` Benjamin Tissoires
0 siblings, 1 reply; 8+ messages in thread
From: Jinmo Yang @ 2026-10-14 10:38 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Dmitry Torokhov, David Barksdale, linux-input, linux-kernel,
Jinmo Yang, stable
cp2112_probe() builds the I2C adapter name from the hidraw minor:
snprintf(dev->adap.name, sizeof(dev->adap.name),
"CP2112 SMBus Bridge on hidraw%d",
((struct hidraw *)hdev->hidraw)->minor);
hdev->hidraw is set only when hidraw_connect() succeeds; on failure it
stays NULL and reading ->minor faults. hidraw_connect() fails when all
HIDRAW_MAX_DEVICES minors are in use, or on allocation failure.
hid_hw_start() does not report that. hid_connect() has
if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
hdev->claimed |= HID_CLAIMED_HIDRAW;
...
if (!hdev->claimed && !hdev->driver->raw_event) {
hid_err(hdev, "device has no listeners, quitting\n");
return -ENODEV;
}
When hidraw_connect() fails, claimed stays 0 -- but that bail-out also
requires the driver to have no ->raw_event. cp2112 sets
.raw_event = cp2112_raw_event, so the -ENODEV path is skipped,
hid_connect() returns 0, cp2112_probe() passes its "if (ret)" check, and
the dereference faults.
The minor is only used for the adapter name, so fall back to the device
name instead of failing the probe.
Found by coverage-guided fuzzing of the HID subsystem through /dev/uhid
(syzkaller with extended descriptions), arm64 with KASAN:
Unable to handle kernel paging request at virtual address dfff800000000000
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
pc : cp2112_probe+0x794/0xef0 drivers/hid/hid-cp2112.c:1333
Call trace:
cp2112_probe
__hid_device_probe
hid_device_probe
really_probe
device_add
hid_add_device
uhid_device_add_worker
process_one_work
hid-led.c and hid-u2fzero.c read hdev->hidraw the same way, but neither
sets ->raw_event, so for them hid_connect() does return -ENODEV and their
error checks catch it. cp2112 is the only one of the three where the
bail-out is defeated.
Fixes: 42cb6b35b9e6 ("HID: cp2112: use proper hidraw name with minor number")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
This is the minimal, backportable fix. Dmitry's series
[PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private
https://lore.kernel.org/linux-input/20261014051326.3784498-1-dmitry.torokhov@gmail.com/
solves the same thing more thoroughly in mainline: 2/5 adds
hidraw_instance(), which performs this check in one place, 3/5 converts
cp2112 (and hid-led and hid-u2fzero) to it, and 5/5 makes the raw cast
impossible by moving hidraw.h out of include/linux. That is the better
end state and I am not proposing an alternative to it.
I am sending this separately only because that series moves headers and
touches include/linux/hid.h, so it is not a stable candidate, while the
dereference itself has been reachable since v4.12. If you would rather
tag 2/5 and 3/5 for stable instead, please drop this patch -- that works
equally well for me and I will not resend it.
Either way the oops is real and unprivileged; the trace above is from
/dev/uhid with no special capabilities. I can test whichever way you go.
drivers/hid/hid-cp2112.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 04379db93571..8883023d432d 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -1330,9 +1330,13 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.algo = &smbus_algorithm;
dev->adap.algo_data = dev;
dev->adap.dev.parent = &hdev->dev;
- snprintf(dev->adap.name, sizeof(dev->adap.name),
- "CP2112 SMBus Bridge on hidraw%d",
- ((struct hidraw *)hdev->hidraw)->minor);
+ if (hdev->claimed & HID_CLAIMED_HIDRAW)
+ snprintf(dev->adap.name, sizeof(dev->adap.name),
+ "CP2112 SMBus Bridge on hidraw%d",
+ ((struct hidraw *)hdev->hidraw)->minor);
+ else
+ snprintf(dev->adap.name, sizeof(dev->adap.name),
+ "CP2112 SMBus Bridge on %s", dev_name(&hdev->dev));
dev->hwversion = buf[2];
init_waitqueue_head(&dev->wait);
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] HID: cp2112: don't dereference hdev->hidraw unconditionally
2026-10-14 10:38 ` [PATCH] HID: cp2112: don't dereference hdev->hidraw unconditionally Jinmo Yang
@ 2026-10-14 13:50 ` Benjamin Tissoires
0 siblings, 0 replies; 8+ messages in thread
From: Benjamin Tissoires @ 2026-10-14 13:50 UTC (permalink / raw)
To: Jinmo Yang
Cc: Jiri Kosina, Dmitry Torokhov, David Barksdale, linux-input,
linux-kernel, stable
Hi Jinmo,
On Oct 14 2026, Jinmo Yang wrote:
> cp2112_probe() builds the I2C adapter name from the hidraw minor:
>
> snprintf(dev->adap.name, sizeof(dev->adap.name),
> "CP2112 SMBus Bridge on hidraw%d",
> ((struct hidraw *)hdev->hidraw)->minor);
>
> hdev->hidraw is set only when hidraw_connect() succeeds; on failure it
> stays NULL and reading ->minor faults. hidraw_connect() fails when all
> HIDRAW_MAX_DEVICES minors are in use, or on allocation failure.
>
> hid_hw_start() does not report that. hid_connect() has
>
> if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
> hdev->claimed |= HID_CLAIMED_HIDRAW;
> ...
> if (!hdev->claimed && !hdev->driver->raw_event) {
> hid_err(hdev, "device has no listeners, quitting\n");
> return -ENODEV;
> }
>
> When hidraw_connect() fails, claimed stays 0 -- but that bail-out also
> requires the driver to have no ->raw_event. cp2112 sets
> .raw_event = cp2112_raw_event, so the -ENODEV path is skipped,
> hid_connect() returns 0, cp2112_probe() passes its "if (ret)" check, and
> the dereference faults.
>
> The minor is only used for the adapter name, so fall back to the device
> name instead of failing the probe.
>
> Found by coverage-guided fuzzing of the HID subsystem through /dev/uhid
> (syzkaller with extended descriptions), arm64 with KASAN:
>
> Unable to handle kernel paging request at virtual address dfff800000000000
> KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
> pc : cp2112_probe+0x794/0xef0 drivers/hid/hid-cp2112.c:1333
> Call trace:
> cp2112_probe
> __hid_device_probe
> hid_device_probe
> really_probe
> device_add
> hid_add_device
> uhid_device_add_worker
> process_one_work
>
> hid-led.c and hid-u2fzero.c read hdev->hidraw the same way, but neither
> sets ->raw_event, so for them hid_connect() does return -ENODEV and their
> error checks catch it. cp2112 is the only one of the three where the
> bail-out is defeated.
>
> Fixes: 42cb6b35b9e6 ("HID: cp2112: use proper hidraw name with minor number")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
> ---
> This is the minimal, backportable fix. Dmitry's series
>
> [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private
> https://lore.kernel.org/linux-input/20261014051326.3784498-1-dmitry.torokhov@gmail.com/
>
> solves the same thing more thoroughly in mainline: 2/5 adds
> hidraw_instance(), which performs this check in one place, 3/5 converts
> cp2112 (and hid-led and hid-u2fzero) to it, and 5/5 makes the raw cast
> impossible by moving hidraw.h out of include/linux. That is the better
> end state and I am not proposing an alternative to it.
Well, you are kind of.
>
> I am sending this separately only because that series moves headers and
> touches include/linux/hid.h, so it is not a stable candidate, while the
> dereference itself has been reachable since v4.12. If you would rather
> tag 2/5 and 3/5 for stable instead, please drop this patch -- that works
> equally well for me and I will not resend it.
Rule of thumbs: upstream shouldn't care about backports to LTS. And
especially in that case: this patch extracts one element from Dmitry's
series, and creates a half backed patch. What about the 3 other drivers
Dmitry fixed?
So yes, there is a bug, it dates back to 4.12 if you say so, but stable
is not my problem FWIW. Given the amount of autoselected patches stable
takes, that's their problem to backport the series, not mine.
As a contributor, you are free to send a [STABLE] series if you care,
but we won't take a lesser quality patch because it's easier to backport.
>
> Either way the oops is real and unprivileged; the trace above is from
> /dev/uhid with no special capabilities. I can test whichever way you go.
Well, unprivileged is wrong here: /dev/uhid should only be root readable
and writeable. If you have a distribution that does make it user
accessible, it's a security hole, and that's their issue. I know some
third party packages are changing the permissions behind the back of the
user, and that's their problem, not our.
Cheers,
Benjamin
>
> drivers/hid/hid-cp2112.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
> index 04379db93571..8883023d432d 100644
> --- a/drivers/hid/hid-cp2112.c
> +++ b/drivers/hid/hid-cp2112.c
> @@ -1330,9 +1330,13 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
> dev->adap.algo = &smbus_algorithm;
> dev->adap.algo_data = dev;
> dev->adap.dev.parent = &hdev->dev;
> - snprintf(dev->adap.name, sizeof(dev->adap.name),
> - "CP2112 SMBus Bridge on hidraw%d",
> - ((struct hidraw *)hdev->hidraw)->minor);
> + if (hdev->claimed & HID_CLAIMED_HIDRAW)
> + snprintf(dev->adap.name, sizeof(dev->adap.name),
> + "CP2112 SMBus Bridge on hidraw%d",
> + ((struct hidraw *)hdev->hidraw)->minor);
> + else
> + snprintf(dev->adap.name, sizeof(dev->adap.name),
> + "CP2112 SMBus Bridge on %s", dev_name(&hdev->dev));
> dev->hwversion = buf[2];
> init_waitqueue_head(&dev->wait);
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-14 13:50 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-14 5:13 [PATCH 0/5] HID: hidraw: Encapsulate struct hidraw and make hidraw.h private Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 1/5] HID: core: Move internal declarations and drop unused exports Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 2/5] HID: hidraw: Introduce hidraw_instance() helper Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 3/5] HID: Use hidraw_instance() in drivers Dmitry Torokhov
2026-10-14 10:38 ` [PATCH] HID: cp2112: don't dereference hdev->hidraw unconditionally Jinmo Yang
2026-10-14 13:50 ` Benjamin Tissoires
2026-10-14 5:13 ` [PATCH 4/5] HID: Drop unused linux/hidraw.h includes Dmitry Torokhov
2026-10-14 5:13 ` [PATCH 5/5] HID: hidraw: Make hidraw.h private to HID subsystem Dmitry Torokhov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®