1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
commit ea2ac1d4c7632717bac2410cfde8a2971aac65af
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date: Sun Aug 17 14:49:51 2025 +0000
usb: dump USB and HID device IDs on HID enumeration
Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index b31b8a2fd..4893fcb4a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -27,6 +27,8 @@
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
+#include <linux/usb.h>
+#include "../usb/core/usb.h"
#include <linux/hid.h>
#include <linux/hiddev.h>
@@ -2632,11 +2634,112 @@ static void hid_free_dynids(struct hid_driver *hdrv)
spin_unlock(&hdrv->dyn_lock);
}
+static void hid_device_id_dump_one(const struct hid_device_id *id, const char *driver_name)
+{
+ char buffer[128];
+ int size = (char *)&id->product + sizeof(id->product) - (char *)id;
+
+ if (id->bus != HID_BUS_ANY && id->bus != BUS_USB)
+ return;
+
+ bin2hex((char *)&buffer[0], (const char *)id, size);
+ buffer[size * 2] = 0;
+ pr_err("HIDID: %s (%s)\n", &buffer[0], driver_name);
+}
+
+static void hid_device_id_dump_static(struct hid_driver *hdrv)
+{
+ const struct hid_device_id *id = hdrv->id_table;
+
+ for (; id->bus; id++)
+ hid_device_id_dump_one(id, hdrv->name);
+}
+
+static void hid_device_id_dump_dynamic(struct hid_driver *hdrv)
+{
+ struct hid_dynid *dynid;
+
+ spin_lock(&hdrv->dyn_lock);
+ list_for_each_entry(dynid, &hdrv->dyn_list, list)
+ hid_device_id_dump_one(&dynid->id, hdrv->name);
+ spin_unlock(&hdrv->dyn_lock);
+}
+
+static int hid_device_id_dump_driver(struct device_driver *drv, void *data)
+{
+ struct hid_driver *hdrv = to_hid_driver(drv);
+
+ hid_device_id_dump_static(hdrv);
+ hid_device_id_dump_dynamic(hdrv);
+
+ return 0;
+}
+
+static void usb_device_id_dump_one(const struct usb_device_id *id, const char *driver_name)
+{
+ char buffer[128];
+ int size = (char *)&id->bInterfaceNumber + sizeof(id->bInterfaceNumber)
+ - (char *)id;
+
+ bin2hex((char *)&buffer[0], (const char *)id, size);
+ buffer[size * 2] = 0;
+ pr_err("USBID: %s (%s)\n", &buffer[0], driver_name);
+}
+
+static void usb_device_id_dump_static(struct usb_driver *drv)
+{
+ const struct usb_device_id *id = drv->id_table;
+
+ if (id == NULL)
+ return;
+
+ for (; id->idVendor || id->idProduct || id->bDeviceClass ||
+ id->bInterfaceClass || id->driver_info; id++)
+ usb_device_id_dump_one(id, drv->name);
+}
+
+static void usb_device_id_dump_dynamic(struct usb_driver *drv)
+{
+ struct usb_dynid *dynid;
+
+ mutex_lock(&usb_dynids_lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node)
+ usb_device_id_dump_one(&dynid->id, drv->name);
+ mutex_unlock(&usb_dynids_lock);
+}
+
+static int usb_device_id_dump_driver(struct device_driver *drv, void *data)
+{
+ struct usb_driver *usb_drv;
+
+ if (is_usb_device_driver(drv))
+ return 0;
+ usb_drv = to_usb_driver(drv);
+
+ usb_device_id_dump_static(usb_drv);
+ usb_device_id_dump_dynamic(usb_drv);
+
+ return 0;
+}
+
+static int usb_ids_dumped;
+
+static void usb_device_id_dump_all(void)
+{
+ if (usb_ids_dumped)
+ return;
+ usb_ids_dumped = 1;
+ bus_for_each_drv(&usb_bus_type, NULL, NULL, usb_device_id_dump_driver);
+ bus_for_each_drv(&hid_bus_type, NULL, NULL, hid_device_id_dump_driver);
+}
+
const struct hid_device_id *hid_match_device(struct hid_device *hdev,
struct hid_driver *hdrv)
{
struct hid_dynid *dynid;
+ usb_device_id_dump_all();
+
spin_lock(&hdrv->dyn_lock);
list_for_each_entry(dynid, &hdrv->dyn_list, list) {
if (hid_match_one_id(hdev, &dynid->id)) {
|