SDL: Use udev to get the manufacturer name if possible (thanks gdb!)

From 4984eb8c168d8c595d0fb0d1d62b47eec2da6f75 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 21 Dec 2025 08:40:21 -0800
Subject: [PATCH] Use udev to get the manufacturer name if possible (thanks
 gdb!)

---
 src/core/linux/SDL_udev.c     |  6 ++++++
 src/core/linux/SDL_udev.h     |  6 ++++++
 src/hidapi/SDL_hidapi_linux.h |  5 +++++
 src/hidapi/linux/hid.c        | 29 +++++++++++++++++++++++++++++
 4 files changed, 46 insertions(+)

diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c
index 3aaa0fb4e9c8c..00bed5e5fc75c 100644
--- a/src/core/linux/SDL_udev.c
+++ b/src/core/linux/SDL_udev.c
@@ -109,6 +109,12 @@ static bool SDL_UDEV_load_syms(void)
     SDL_UDEV_SYM(udev_unref);
     SDL_UDEV_SYM(udev_device_new_from_devnum);
     SDL_UDEV_SYM(udev_device_get_devnum);
+
+    SDL_UDEV_SYM(udev_hwdb_new);
+    SDL_UDEV_SYM(udev_hwdb_unref);
+    SDL_UDEV_SYM(udev_hwdb_get_properties_list_entry);
+    SDL_UDEV_SYM(udev_list_entry_get_value);
+
 #undef SDL_UDEV_SYM
 
     return true;
diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h
index f2b1ce56e2702..3f69ce6237d40 100644
--- a/src/core/linux/SDL_udev.h
+++ b/src/core/linux/SDL_udev.h
@@ -83,6 +83,12 @@ typedef struct SDL_UDEV_Symbols
     void (*udev_unref)(struct udev *);
     struct udev_device *(*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
     dev_t (*udev_device_get_devnum)(struct udev_device *udev_device);
+
+    struct udev_hwdb *(*udev_hwdb_new)(struct udev *udev);
+    struct udev_hwdb *(*udev_hwdb_unref)(struct udev_hwdb *hwdb);
+    struct udev_list_entry *(*udev_hwdb_get_properties_list_entry)(struct udev_hwdb *hwdb, const char *modalias, unsigned flags);
+    const char *(*udev_list_entry_get_value)(struct udev_list_entry *list_entry);
+
 } SDL_UDEV_Symbols;
 
 typedef struct SDL_UDEV_PrivateData
diff --git a/src/hidapi/SDL_hidapi_linux.h b/src/hidapi/SDL_hidapi_linux.h
index 8418e2e92885f..eaa04e4800c1c 100644
--- a/src/hidapi/SDL_hidapi_linux.h
+++ b/src/hidapi/SDL_hidapi_linux.h
@@ -39,6 +39,11 @@ static const SDL_UDEV_Symbols *udev_ctx = NULL;
 #define udev_new                                      udev_ctx->udev_new
 #define udev_unref                                    udev_ctx->udev_unref
 
+#define udev_hwdb_new                                 udev_ctx->udev_hwdb_new 
+#define udev_hwdb_unref                               udev_ctx->udev_hwdb_unref
+#define udev_hwdb_get_properties_list_entry           udev_ctx->udev_hwdb_get_properties_list_entry
+#define udev_list_entry_get_value                     udev_ctx->udev_list_entry_get_value
+
 #undef HIDAPI_H__
 #define HIDAPI_ALLOW_BUILD_WORKAROUND_KERNEL_2_6_39
 #include "linux/hid.c"
diff --git a/src/hidapi/linux/hid.c b/src/hidapi/linux/hid.c
index c0cb6a7b0e255..9bb781a79d972 100644
--- a/src/hidapi/linux/hid.c
+++ b/src/hidapi/linux/hid.c
@@ -1008,6 +1008,13 @@ int HID_API_EXPORT hid_exit(void)
 
 struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 {
+	struct udev_hwdb *hwdb = NULL;
+	struct udev_list_entry *entry;
+
+	char modalias[64];
+	const char *key;
+	const char *manufacturer_string;
+
 	struct udev *udev;
 	struct udev_enumerate *enumerate;
 	struct udev_list_entry *devices, *dev_list_entry;
@@ -1060,8 +1067,30 @@ struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
 		if (!raw_dev)
 			continue;
 
+
 		tmp = create_device_info_for_device(raw_dev);
+
 		if (tmp) {
+			if (!tmp->manufacturer_string) {
+				key = "ID_VENDOR_FROM_DATABASE";
+
+				if ((hwdb = udev_hwdb_new(udev)) != NULL) {
+					snprintf(modalias, sizeof(modalias), "usb:v%04X*", vendor_id);
+
+					udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) {
+						if (strcmp(udev_list_entry_get_name(entry), key) == 0) {
+							manufacturer_string = udev_list_entry_get_value(entry);
+							if (manufacturer_string) {
+								tmp->manufacturer_string = utf8_to_wchar_t(manufacturer_string);
+							}
+							break;
+						}
+					}
+
+					hwdb = udev_hwdb_unref(hwdb);
+				}
+			}
+
 			if (cur_dev) {
 				cur_dev->next = tmp;
 			}