From 54f129f765e8418ad47178f24fef5935c9d18947 Mon Sep 17 00:00:00 2001
From: pmx <[EMAIL REDACTED]>
Date: Wed, 12 Nov 2025 23:25:31 +0100
Subject: [PATCH] FIX SDL_GetJoystickSerial() always returning NULL on Linux
(UDEV) (#14454)
---
src/core/linux/SDL_udev.c | 37 ++++++++++++++++++++++++++++
src/core/linux/SDL_udev.h | 1 +
src/joystick/linux/SDL_sysjoystick.c | 7 ++++++
3 files changed, 45 insertions(+)
diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c
index 2903ec34b4265..1a2ba4df81df9 100644
--- a/src/core/linux/SDL_udev.c
+++ b/src/core/linux/SDL_udev.c
@@ -302,6 +302,43 @@ bool SDL_UDEV_GetProductInfo(const char *device_path, struct input_id *inpid, in
return true;
}
+bool SDL_UDEV_GetProductSerial(const char *device_path, const char **serial)
+{
+ struct stat statbuf;
+ char type;
+ struct udev_device *dev;
+ const char *val;
+
+ if (!_this) {
+ return false;
+ }
+
+ if (stat(device_path, &statbuf) < 0) {
+ return false;
+ }
+
+ if (S_ISBLK(statbuf.st_mode)) {
+ type = 'b';
+ } else if (S_ISCHR(statbuf.st_mode)) {
+ type = 'c';
+ } else {
+ return false;
+ }
+
+ dev = _this->syms.udev_device_new_from_devnum(_this->udev, type, statbuf.st_rdev);
+ if (!dev) {
+ return false;
+ }
+
+ val = _this->syms.udev_device_get_property_value(dev, "ID_SERIAL_SHORT");
+ if (val) {
+ *serial = val;
+ return true;
+ }
+
+ return false;
+}
+
void SDL_UDEV_UnloadLibrary(void)
{
if (!_this) {
diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h
index e99d06a5bee84..fbe422077642e 100644
--- a/src/core/linux/SDL_udev.h
+++ b/src/core/linux/SDL_udev.h
@@ -105,6 +105,7 @@ extern bool SDL_UDEV_LoadLibrary(void);
extern void SDL_UDEV_Poll(void);
extern bool SDL_UDEV_Scan(void);
extern bool SDL_UDEV_GetProductInfo(const char *device_path, struct input_id *inpid, int *class, char **driver);
+extern bool SDL_UDEV_GetProductSerial(const char *device_path, const char **serial);
extern bool SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
extern const SDL_UDEV_Symbols *SDL_UDEV_GetUdevSyms(void);
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index d4bb97908114e..c94658f6e01e4 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -1608,6 +1608,13 @@ static bool LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
item_sensor->hwdata = joystick->hwdata;
}
+#ifdef SDL_USE_LIBUDEV
+ const char *serial = NULL;
+ if (SDL_UDEV_GetProductSerial(item->path, &serial)) {
+ joystick->serial = SDL_strdup(serial);
+ }
+#endif
+
// mark joystick as fresh and ready
joystick->hwdata->fresh = true;