Commit b17242bf9839a3796d82264f653df2dd4d416f9b

Ludovico de Nittis 2021-02-16T11:50:20

Allow libudev for HIDAPI joystick to be disabled at runtime As already explained in the previous commit "joystick: Allow libudev to be disabled at runtime" (13e7d1a9), libudev can fail in a container. To make it easier to experiment with, we add a new environment variable "SDL_HIDAPI_JOYSTICK_DISABLE_UDEV" that disables udev and let it fallback to the device enumeration using polling. Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com>

diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index d73ba40..e751bb1 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -28,6 +28,7 @@
 #include "SDL_thread.h"
 #include "SDL_timer.h"
 #include "SDL_joystick.h"
+#include "SDL_log.h"
 #include "../SDL_sysjoystick.h"
 #include "SDL_hidapijoystick_c.h"
 #include "SDL_hidapi_rumble.h"
@@ -53,6 +54,15 @@
 #endif
 #endif
 
+typedef enum
+{
+    ENUMERATION_UNSET,
+    ENUMERATION_LIBUDEV,
+    ENUMERATION_FALLBACK
+} LinuxEnumerationMethod;
+
+static LinuxEnumerationMethod linux_enumeration_method = ENUMERATION_UNSET;
+
 struct joystick_hwdata
 {
     SDL_HIDAPI_Device *device;
@@ -273,23 +283,24 @@ HIDAPI_InitializeDiscovery()
 #endif // __MACOSX__
 
 #if defined(SDL_USE_LIBUDEV)
-    SDL_HIDAPI_discovery.m_pUdev = NULL;
-    SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
-    SDL_HIDAPI_discovery.m_nUdevFd = -1;
-
-    usyms = SDL_UDEV_GetUdevSyms();
-    if (usyms) {
-        SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
-    }
-    if (SDL_HIDAPI_discovery.m_pUdev) {
-        SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
-        if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
-            usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
-            SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
-            SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
+    if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
+        SDL_HIDAPI_discovery.m_pUdev = NULL;
+        SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
+        SDL_HIDAPI_discovery.m_nUdevFd = -1;
+
+        usyms = SDL_UDEV_GetUdevSyms();
+        if (usyms) {
+            SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
+        }
+        if (SDL_HIDAPI_discovery.m_pUdev) {
+            SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
+            if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
+                usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
+                SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
+                SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
+            }
         }
     }
-
 #endif /* SDL_USE_LIBUDEV */
 }
 
@@ -331,31 +342,33 @@ HIDAPI_UpdateDiscovery()
 #endif
 
 #if defined(SDL_USE_LIBUDEV)
-    if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
-        /* Drain all notification events.
-         * We don't expect a lot of device notifications so just
-         * do a new discovery on any kind or number of notifications.
-         * This could be made more restrictive if necessary.
-         */
-        for (;;) {
-            struct pollfd PollUdev;
-            struct udev_device *pUdevDevice;
-
-            PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
-            PollUdev.events = POLLIN;
-            if (poll(&PollUdev, 1, 0) != 1) {
-                break;
-            }
+    if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
+        if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
+            /* Drain all notification events.
+             * We don't expect a lot of device notifications so just
+             * do a new discovery on any kind or number of notifications.
+             * This could be made more restrictive if necessary.
+             */
+            for (;;) {
+                struct pollfd PollUdev;
+                struct udev_device *pUdevDevice;
+
+                PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
+                PollUdev.events = POLLIN;
+                if (poll(&PollUdev, 1, 0) != 1) {
+                    break;
+                }
 
-            SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
+                SDL_HIDAPI_discovery.m_bHaveDevicesChanged = SDL_TRUE;
 
-            pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
-            if (pUdevDevice) {
-                usyms->udev_device_unref(pUdevDevice);
+                pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
+                if (pUdevDevice) {
+                    usyms->udev_device_unref(pUdevDevice);
+                }
             }
         }
     }
-#endif
+#endif /* SDL_USE_LIBUDEV */
 }
 
 static void
@@ -379,7 +392,8 @@ HIDAPI_ShutdownDiscovery()
 #endif
 
 #if defined(SDL_USE_LIBUDEV)
-    if (usyms) {
+    if (linux_enumeration_method == ENUMERATION_LIBUDEV &&
+        usyms) {
         if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
             usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor);
         }
@@ -600,6 +614,20 @@ HIDAPI_JoystickInit(void)
         return 0;
     }
 
+#if defined(SDL_USE_LIBUDEV)
+    if (linux_enumeration_method == ENUMERATION_UNSET) {
+        if (SDL_getenv("SDL_HIDAPI_JOYSTICK_DISABLE_UDEV") != NULL) {
+            SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
+                         "udev disabled by SDL_HIDAPI_JOYSTICK_DISABLE_UDEV");
+            linux_enumeration_method = ENUMERATION_FALLBACK;
+        } else {
+            SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
+                         "Using udev for HIDAPI joystick device discovery");
+            linux_enumeration_method = ENUMERATION_LIBUDEV;
+        }
+    }
+#endif
+
 #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
     /* The hidapi framwork is weak-linked on Apple platforms */
     int HID_API_EXPORT HID_API_CALL hid_init(void) __attribute__((weak_import));