Commit 4e682461cc6668c860405560446ae33de3490f27

Sam Lantinga 2020-01-17T10:43:14

Reattach the kernel driver after closing USB controllers

diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c
index 1e54e30..1cf3e1b 100644
--- a/src/hidapi/SDL_hidapi.c
+++ b/src/hidapi/SDL_hidapi.c
@@ -165,6 +165,7 @@ static struct
     int (*release_interface)(libusb_device_handle *dev_handle, int interface_number);
     int (*kernel_driver_active)(libusb_device_handle *dev_handle, int interface_number);
     int (*detach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number);
+    int (*attach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number);
     int (*set_interface_alt_setting)(libusb_device_handle *dev, int interface_number, int alternate_setting);
     struct libusb_transfer * (*alloc_transfer)(int iso_packets);
     int (*submit_transfer)(struct libusb_transfer *transfer);
@@ -208,6 +209,7 @@ static struct
 #define libusb_release_interface               libusb_ctx.release_interface
 #define libusb_kernel_driver_active            libusb_ctx.kernel_driver_active
 #define libusb_detach_kernel_driver            libusb_ctx.detach_kernel_driver
+#define libusb_attach_kernel_driver            libusb_ctx.attach_kernel_driver
 #define libusb_set_interface_alt_setting       libusb_ctx.set_interface_alt_setting
 #define libusb_alloc_transfer                  libusb_ctx.alloc_transfer
 #define libusb_submit_transfer                 libusb_ctx.submit_transfer
@@ -474,6 +476,7 @@ int HID_API_EXPORT HID_API_CALL hid_init(void)
         LOAD_LIBUSB_SYMBOL(release_interface)
         LOAD_LIBUSB_SYMBOL(kernel_driver_active)
         LOAD_LIBUSB_SYMBOL(detach_kernel_driver)
+        LOAD_LIBUSB_SYMBOL(attach_kernel_driver)
         LOAD_LIBUSB_SYMBOL(set_interface_alt_setting)
         LOAD_LIBUSB_SYMBOL(alloc_transfer)
         LOAD_LIBUSB_SYMBOL(submit_transfer)
diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c
index d6dfaf3..967c86f 100644
--- a/src/hidapi/libusb/hid.c
+++ b/src/hidapi/libusb/hid.c
@@ -141,6 +141,7 @@ struct hid_device_ {
 
 	/* The interface number of the HID */
 	int interface;
+	int detached_driver;
 
 	/* Indexes of Strings */
 	int manufacturer_index;
@@ -983,6 +984,8 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 				if (should_enumerate_interface(desc.idVendor, intf_desc)) {
 					char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
 					if (!strcmp(dev_path, path)) {
+						int detached_driver = 0;
+
 						/* Matched Paths. Open this device */
 
 						/* OPEN HERE */
@@ -1006,6 +1009,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 								good_open = 0;
 								break;
 							}
+							detached_driver = 1;
 						}
 #endif
 
@@ -1030,6 +1034,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 
 						/* Store off the interface number */
 						dev->interface = intf_desc->bInterfaceNumber;
+						dev->detached_driver = detached_driver;
 
 						/* Find the INPUT and OUTPUT endpoints. An
 						   OUTPUT endpoint is not required. */
@@ -1335,6 +1340,15 @@ void HID_API_EXPORT hid_close(hid_device *dev)
 	/* release the interface */
 	libusb_release_interface(dev->device_handle, dev->interface);
 
+#ifdef DETACH_KERNEL_DRIVER
+	/* Re-attach kernel driver if necessary. */
+	if (dev->detached_driver) {
+		int res = libusb_attach_kernel_driver(dev->device_handle, dev->interface);
+		if (res < 0)
+			LOG("Couldn't re-attach kernel driver.\n");
+	}
+#endif
+
 	/* Close the handle */
 	libusb_close(dev->device_handle);
 
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 768dc74..2ae57e6 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -844,6 +844,14 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, cons
     }
     SDL_UnlockJoysticks();
 
+    /* If we're looking for the wireless XBox 360 controller, also look for the dongle */
+    if (!result && vendor_id == 0x045e && product_id == 0x02a1) {
+        return HIDAPI_IsDevicePresent(0x045e, 0x0719, version, name);
+    }
+
+#ifdef DEBUG_HIDAPI
+    SDL_Log("HIDAPI_IsDevicePresent() returning %s for 0x%.4x / 0x%.4x\n", result ? "true" : "false", vendor_id, product_id);
+#endif
     return result;
 }