commit ea2ac1d4c7632717bac2410cfde8a2971aac65af Author: Andrey Konovalov Date: Sun Aug 17 14:49:51 2025 +0000 usb: dump USB and HID device IDs on HID enumeration Signed-off-by: Andrey Konovalov 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 #include #include +#include +#include "../usb/core/usb.h" #include #include @@ -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)) {