Просмотр исходного кода

Fixed initializing EVORETRO GameCube adapters

The HID device needs to be closed while enabling input reports over USB
Sam Lantinga 3 месяцев назад
Родитель
Сommit
9f444b3981
3 измененных файлов с 79 добавлено и 78 удалено
  1. 0 57
      src/hidapi/SDL_hidapi.c
  2. 0 9
      src/hidapi/SDL_hidapi_c.h
  3. 79 12
      src/joystick/hidapi/SDL_hidapi_gamecube.c

+ 0 - 57
src/hidapi/SDL_hidapi.c

@@ -1619,60 +1619,3 @@ void SDL_hid_ble_scan(bool active)
     hid_ble_scan(active);
 #endif
 }
-
-#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
-// This is needed to enable input for Nyko and EVORETRO GameCube adaptors
-void SDL_EnableGameCubeAdaptors(void)
-{
-#ifdef HAVE_LIBUSB
-    libusb_context *context = NULL;
-    libusb_device **devs = NULL;
-    libusb_device_handle *handle = NULL;
-    struct libusb_device_descriptor desc;
-    ssize_t i, num_devs;
-    int kernel_detached = 0;
-
-    if (!libusb_ctx) {
-        return;
-    }
-
-    if (libusb_ctx->init(&context) == 0) {
-        num_devs = libusb_ctx->get_device_list(context, &devs);
-        for (i = 0; i < num_devs; ++i) {
-            if (libusb_ctx->get_device_descriptor(devs[i], &desc) != 0) {
-                continue;
-            }
-
-            if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) {
-                continue;
-            }
-
-            if (libusb_ctx->open(devs[i], &handle) != 0) {
-                continue;
-            }
-
-            if (libusb_ctx->kernel_driver_active(handle, 0)) {
-                if (libusb_ctx->detach_kernel_driver(handle, 0) == 0) {
-                    kernel_detached = 1;
-                }
-            }
-
-            if (libusb_ctx->claim_interface(handle, 0) == 0) {
-                libusb_ctx->control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000);
-                libusb_ctx->release_interface(handle, 0);
-            }
-
-            if (kernel_detached) {
-                libusb_ctx->attach_kernel_driver(handle, 0);
-            }
-
-            libusb_ctx->close(handle);
-        }
-
-        libusb_ctx->free_device_list(devs, 1);
-
-        libusb_ctx->exit(context);
-    }
-#endif // HAVE_LIBUSB
-}
-#endif // HAVE_ENABLE_GAMECUBE_ADAPTORS

+ 0 - 9
src/hidapi/SDL_hidapi_c.h

@@ -24,12 +24,3 @@
 /* Return true if the HIDAPI should ignore a device during enumeration */
 extern bool SDL_HIDAPI_ShouldIgnoreDevice(int bus_type, Uint16 vendor_id, Uint16 product_id, Uint16 usage_page, Uint16 usage);
 
-#ifdef SDL_JOYSTICK_HIDAPI
-#ifdef HAVE_LIBUSB
-#define HAVE_ENABLE_GAMECUBE_ADAPTORS
-#endif
-
-#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
-extern void SDL_EnableGameCubeAdaptors(void);
-#endif
-#endif /* SDL_JOYSTICK_HIDAPI */

+ 79 - 12
src/joystick/hidapi/SDL_hidapi_gamecube.c

@@ -23,6 +23,7 @@
 #ifdef SDL_JOYSTICK_HIDAPI
 
 #include "../../SDL_hints_c.h"
+#include "../../misc/SDL_libusb.h"
 #include "../SDL_sysjoystick.h"
 #include "SDL_hidapijoystick_c.h"
 #include "SDL_hidapi_rumble.h"
@@ -102,6 +103,83 @@ static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, c
     }
 }
 
+static bool HIDAPI_DriverGameCube_EnableAdapter(SDL_HIDAPI_Device *device)
+{
+#ifdef HAVE_LIBUSB
+    // Need to close the device while sending USB commands to it
+    SDL_hid_close(device->dev);
+
+    // This is needed to enable input for Nyko and EVORETRO GameCube adapters
+    SDL_LibUSBContext *libusb_ctx;
+    if (SDL_InitLibUSB(&libusb_ctx)) {
+        libusb_context *context = NULL;
+        libusb_device **devs = NULL;
+        libusb_device_handle *handle = NULL;
+        struct libusb_device_descriptor desc;
+        ssize_t i, num_devs;
+        bool kernel_detached = false;
+
+        if (libusb_ctx->init(&context) == 0) {
+            num_devs = libusb_ctx->get_device_list(context, &devs);
+            for (i = 0; i < num_devs; ++i) {
+                if (libusb_ctx->get_device_descriptor(devs[i], &desc) != 0) {
+                    continue;
+                }
+
+                if (desc.idVendor != USB_VENDOR_NINTENDO ||
+                    desc.idProduct != USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) {
+                    continue;
+                }
+
+                if (libusb_ctx->open(devs[i], &handle) != 0) {
+                    continue;
+                }
+
+                if (libusb_ctx->kernel_driver_active(handle, 0)) {
+                    if (libusb_ctx->detach_kernel_driver(handle, 0) == 0) {
+                        kernel_detached = true;
+                    }
+                }
+
+                if (libusb_ctx->claim_interface(handle, 0) == 0) {
+                    libusb_ctx->control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000);
+                    libusb_ctx->release_interface(handle, 0);
+                }
+
+                if (kernel_detached) {
+                    libusb_ctx->attach_kernel_driver(handle, 0);
+                }
+
+                libusb_ctx->close(handle);
+            }
+
+            libusb_ctx->free_device_list(devs, 1);
+
+            libusb_ctx->exit(context);
+        }
+        SDL_QuitLibUSB();
+    }
+
+    // Reopen the device now that we're done
+    device->dev = SDL_hid_open_path(device->path);
+    if (!device->dev) {
+        return false;
+    }
+#endif // HAVE_LIBUSB
+
+    Uint8 initMagic = 0x13;
+    if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
+        SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
+                     "HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
+        return false;
+    }
+
+    // Wait for the adapter to initialize
+    SDL_Delay(10);
+
+    return true;
+}
+
 static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
 {
     SDL_DriverGameCube_Context *ctx;
@@ -109,13 +187,8 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
     Uint8 *curSlot;
     Uint8 i;
     int size;
-    Uint8 initMagic = 0x13;
     Uint8 rumbleMagic = 0x11;
 
-#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
-    SDL_EnableGameCubeAdaptors();
-#endif
-
     ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
     if (!ctx) {
         return false;
@@ -132,16 +205,10 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
         ResetAxisRange(ctx, 0);
         HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
     } else {
-        // This is all that's needed to initialize the device. Really!
-        if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
-            SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
-                         "HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
+        if (!HIDAPI_DriverGameCube_EnableAdapter(device)) {
             return false;
         }
 
-        // Wait for the adapter to initialize
-        SDL_Delay(10);
-
         // Add all the applicable joysticks
         while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
 #ifdef DEBUG_GAMECUBE_PROTOCOL