|
@@ -888,8 +888,7 @@ static const struct {
|
|
|
{ 0x057e, 0x0337 } /* Nintendo WUP-028, Wii U/Switch GameCube Adapter */
|
|
|
};
|
|
|
|
|
|
-static SDL_bool
|
|
|
-IsInWhitelist(Uint16 vendor, Uint16 product)
|
|
|
+static SDL_bool IsInWhitelist(Uint16 vendor, Uint16 product)
|
|
|
{
|
|
|
int i;
|
|
|
for (i = 0; i < SDL_arraysize(SDL_libusb_whitelist); i += 1) {
|
|
@@ -901,6 +900,10 @@ IsInWhitelist(Uint16 vendor, Uint16 product)
|
|
|
return SDL_FALSE;
|
|
|
}
|
|
|
|
|
|
+#endif /* HAVE_LIBUSB */
|
|
|
+
|
|
|
+#endif /* !SDL_HIDAPI_DISABLED */
|
|
|
+
|
|
|
#if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND
|
|
|
/* We have another way to get HID devices, so use the whitelist to get devices where libusb is preferred */
|
|
|
#define SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT SDL_TRUE
|
|
@@ -911,10 +914,6 @@ IsInWhitelist(Uint16 vendor, Uint16 product)
|
|
|
|
|
|
static SDL_bool use_libusb_whitelist = SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT;
|
|
|
|
|
|
-#endif /* HAVE_LIBUSB */
|
|
|
-
|
|
|
-#endif /* !SDL_HIDAPI_DISABLED */
|
|
|
-
|
|
|
/* Shared HIDAPI Implementation */
|
|
|
|
|
|
struct hidapi_backend
|
|
@@ -1155,9 +1154,9 @@ int SDL_hid_init(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-#ifdef HAVE_LIBUSB
|
|
|
use_libusb_whitelist = SDL_GetHintBoolean("SDL_HIDAPI_LIBUSB_WHITELIST",
|
|
|
SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT);
|
|
|
+#ifdef HAVE_LIBUSB
|
|
|
if (SDL_getenv("SDL_HIDAPI_DISABLE_LIBUSB") != NULL) {
|
|
|
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
|
|
"libusb disabled by SDL_HIDAPI_DISABLE_LIBUSB");
|
|
@@ -1320,154 +1319,168 @@ Uint32 SDL_hid_device_change_count(void)
|
|
|
return counter;
|
|
|
}
|
|
|
|
|
|
-struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
|
|
+static void AddDeviceToEnumeration(const char *driver_name, struct hid_device_info *dev, struct SDL_hid_device_info **devs, struct SDL_hid_device_info **last)
|
|
|
{
|
|
|
-#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB)
|
|
|
-#ifdef HAVE_LIBUSB
|
|
|
- struct hid_device_info *usb_devs = NULL;
|
|
|
- struct hid_device_info *usb_dev;
|
|
|
-#endif
|
|
|
-#ifdef HAVE_DRIVER_BACKEND
|
|
|
- struct hid_device_info *driver_devs = NULL;
|
|
|
- struct hid_device_info *driver_dev;
|
|
|
-#endif
|
|
|
-#ifdef HAVE_PLATFORM_BACKEND
|
|
|
- struct hid_device_info *raw_devs = NULL;
|
|
|
- struct hid_device_info *raw_dev;
|
|
|
+ struct SDL_hid_device_info *new_dev;
|
|
|
+
|
|
|
+#ifdef DEBUG_HIDAPI
|
|
|
+ SDL_Log("Adding %s device to enumeration: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
|
|
+ driver_name, dev->manufacturer_string, dev->product_string, dev->vendor_id, dev->product_id, dev->interface_number);
|
|
|
+#else
|
|
|
+ (void)driver_name;
|
|
|
#endif
|
|
|
- struct SDL_hid_device_info *devs = NULL, *last = NULL, *new_dev;
|
|
|
|
|
|
- if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
|
|
|
- return NULL;
|
|
|
+ new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
|
|
+ if (new_dev == NULL) {
|
|
|
+ /* Don't bother returning an error, get as many devices as possible */
|
|
|
+ return;
|
|
|
}
|
|
|
+ CopyHIDDeviceInfo(dev, new_dev);
|
|
|
|
|
|
-#ifdef HAVE_LIBUSB
|
|
|
- if (libusb_ctx.libhandle) {
|
|
|
- usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
|
|
|
+ if ((*last) != NULL) {
|
|
|
+ (*last)->next = new_dev;
|
|
|
+ } else {
|
|
|
+ *devs = new_dev;
|
|
|
+ }
|
|
|
+ *last = new_dev;
|
|
|
+}
|
|
|
+
|
|
|
+static void RemoveDeviceFromEnumeration(const char *driver_name, struct hid_device_info *dev, struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *))
|
|
|
+{
|
|
|
+ struct hid_device_info *last = NULL, *curr, *next;
|
|
|
+
|
|
|
+ for (curr = *devs; curr; curr = next) {
|
|
|
+ next = curr->next;
|
|
|
+
|
|
|
+ if (dev->vendor_id == curr->vendor_id &&
|
|
|
+ dev->product_id == curr->product_id &&
|
|
|
+ (dev->interface_number < 0 || curr->interface_number < 0 || dev->interface_number == curr->interface_number)) {
|
|
|
#ifdef DEBUG_HIDAPI
|
|
|
- SDL_Log("libusb devices found:");
|
|
|
+ SDL_Log("Skipping %s device: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
|
|
+ driver_name, curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number);
|
|
|
+#else
|
|
|
+ (void)driver_name;
|
|
|
#endif
|
|
|
- for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
|
|
|
- if (use_libusb_whitelist) {
|
|
|
- if (!IsInWhitelist(usb_dev->vendor_id, usb_dev->product_id)) {
|
|
|
-#ifdef DEBUG_HIDAPI
|
|
|
- SDL_Log("Device was not in libusb whitelist: %ls %ls 0x%.4hx 0x%.4hx",
|
|
|
- usb_dev->manufacturer_string, usb_dev->product_string,
|
|
|
- usb_dev->vendor_id, usb_dev->product_id);
|
|
|
-#endif /* DEBUG_HIDAPI */
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
|
|
- if (new_dev == NULL) {
|
|
|
- LIBUSB_hid_free_enumeration(usb_devs);
|
|
|
- SDL_hid_free_enumeration(devs);
|
|
|
- SDL_OutOfMemory();
|
|
|
- return NULL;
|
|
|
+ if (last) {
|
|
|
+ last->next = next;
|
|
|
+ } else {
|
|
|
+ *devs = next;
|
|
|
}
|
|
|
- CopyHIDDeviceInfo(usb_dev, new_dev);
|
|
|
+
|
|
|
+ curr->next = NULL;
|
|
|
+ free_device_info(curr);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ last = curr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef HAVE_LIBUSB
|
|
|
+static void RemoveNonWhitelistedDevicesFromEnumeration(struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *))
|
|
|
+{
|
|
|
+ struct hid_device_info *last = NULL, *curr, *next;
|
|
|
+
|
|
|
+ for (curr = *devs; curr; curr = next) {
|
|
|
+ next = curr->next;
|
|
|
+
|
|
|
+ if (!IsInWhitelist(curr->vendor_id, curr->product_id)) {
|
|
|
#ifdef DEBUG_HIDAPI
|
|
|
- SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
|
|
|
- usb_dev->manufacturer_string, usb_dev->product_string,
|
|
|
- usb_dev->vendor_id, usb_dev->product_id);
|
|
|
+ SDL_Log("Device was not in libusb whitelist, skipping: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
|
|
+ curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number);
|
|
|
#endif
|
|
|
-
|
|
|
- if (last != NULL) {
|
|
|
- last->next = new_dev;
|
|
|
+ if (last) {
|
|
|
+ last->next = next;
|
|
|
} else {
|
|
|
- devs = new_dev;
|
|
|
+ *devs = next;
|
|
|
}
|
|
|
- last = new_dev;
|
|
|
+
|
|
|
+ curr->next = NULL;
|
|
|
+ free_device_info(curr);
|
|
|
+ continue;
|
|
|
}
|
|
|
+ last = curr;
|
|
|
}
|
|
|
+}
|
|
|
#endif /* HAVE_LIBUSB */
|
|
|
|
|
|
+struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
|
|
+{
|
|
|
+ struct hid_device_info *driver_devs = NULL;
|
|
|
+ struct hid_device_info *usb_devs = NULL;
|
|
|
+ struct hid_device_info *raw_devs = NULL;
|
|
|
+ struct hid_device_info *dev;
|
|
|
+ struct SDL_hid_device_info *devs = NULL, *last = NULL;
|
|
|
+
|
|
|
+ if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Collect the available devices */
|
|
|
#ifdef HAVE_DRIVER_BACKEND
|
|
|
driver_devs = DRIVER_hid_enumerate(vendor_id, product_id);
|
|
|
- for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
|
|
|
- new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
|
|
- CopyHIDDeviceInfo(driver_dev, new_dev);
|
|
|
+#endif
|
|
|
|
|
|
- if (last != NULL) {
|
|
|
- last->next = new_dev;
|
|
|
- } else {
|
|
|
- devs = new_dev;
|
|
|
+#ifdef HAVE_LIBUSB
|
|
|
+ if (libusb_ctx.libhandle) {
|
|
|
+ usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
|
|
|
+
|
|
|
+ if (use_libusb_whitelist) {
|
|
|
+ RemoveNonWhitelistedDevicesFromEnumeration(&usb_devs, LIBUSB_hid_free_enumeration);
|
|
|
}
|
|
|
- last = new_dev;
|
|
|
}
|
|
|
-#endif /* HAVE_DRIVER_BACKEND */
|
|
|
+#endif /* HAVE_LIBUSB */
|
|
|
|
|
|
#ifdef HAVE_PLATFORM_BACKEND
|
|
|
if (udev_ctx) {
|
|
|
raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id);
|
|
|
-#ifdef DEBUG_HIDAPI
|
|
|
- SDL_Log("hidraw devices found:");
|
|
|
-#endif
|
|
|
- for (raw_dev = raw_devs; raw_dev; raw_dev = raw_dev->next) {
|
|
|
- SDL_bool bFound = SDL_FALSE;
|
|
|
-#ifdef DEBUG_HIDAPI
|
|
|
- SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
|
|
|
- raw_dev->manufacturer_string, raw_dev->product_string,
|
|
|
- raw_dev->vendor_id, raw_dev->product_id);
|
|
|
+ }
|
|
|
#endif
|
|
|
+
|
|
|
+ /* Highest priority are custom driver devices */
|
|
|
+ for (dev = driver_devs; dev; dev = dev->next) {
|
|
|
+ AddDeviceToEnumeration("driver", dev, &devs, &last);
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
- for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
|
|
|
- if (raw_dev->vendor_id == usb_dev->vendor_id &&
|
|
|
- raw_dev->product_id == usb_dev->product_id &&
|
|
|
- (raw_dev->interface_number < 0 || raw_dev->interface_number == usb_dev->interface_number)) {
|
|
|
- bFound = SDL_TRUE;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration);
|
|
|
#endif
|
|
|
-#ifdef HAVE_DRIVER_BACKEND
|
|
|
- for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
|
|
|
- if (raw_dev->vendor_id == driver_dev->vendor_id &&
|
|
|
- raw_dev->product_id == driver_dev->product_id &&
|
|
|
- (raw_dev->interface_number < 0 || raw_dev->interface_number == driver_dev->interface_number)) {
|
|
|
- bFound = SDL_TRUE;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+#ifdef HAVE_PLATFORM_BACKEND
|
|
|
+ RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration);
|
|
|
#endif
|
|
|
- if (!bFound) {
|
|
|
- new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
|
|
- if (new_dev == NULL) {
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If whitelist is in effect, libusb has priority, otherwise raw devices do */
|
|
|
+ if (use_libusb_whitelist) {
|
|
|
+ for (dev = usb_devs; dev; dev = dev->next) {
|
|
|
+ AddDeviceToEnumeration("libusb", dev, &devs, &last);
|
|
|
+#ifdef HAVE_PLATFORM_BACKEND
|
|
|
+ RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ for (dev = raw_devs; dev; dev = dev->next) {
|
|
|
+ AddDeviceToEnumeration("platform", dev, &devs, &last);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (dev = raw_devs; dev; dev = dev->next) {
|
|
|
+ AddDeviceToEnumeration("raw", dev, &devs, &last);
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
- if (libusb_ctx.libhandle) {
|
|
|
- LIBUSB_hid_free_enumeration(usb_devs);
|
|
|
- }
|
|
|
+ RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration);
|
|
|
#endif
|
|
|
- PLATFORM_hid_free_enumeration(raw_devs);
|
|
|
- SDL_hid_free_enumeration(devs);
|
|
|
- SDL_OutOfMemory();
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- CopyHIDDeviceInfo(raw_dev, new_dev);
|
|
|
- new_dev->next = NULL;
|
|
|
-
|
|
|
- if (last != NULL) {
|
|
|
- last->next = new_dev;
|
|
|
- } else {
|
|
|
- devs = new_dev;
|
|
|
- }
|
|
|
- last = new_dev;
|
|
|
- }
|
|
|
}
|
|
|
- PLATFORM_hid_free_enumeration(raw_devs);
|
|
|
+ for (dev = usb_devs; dev; dev = dev->next) {
|
|
|
+ AddDeviceToEnumeration("libusb", dev, &devs, &last);
|
|
|
+ }
|
|
|
}
|
|
|
-#endif /* HAVE_PLATFORM_BACKEND */
|
|
|
|
|
|
+#ifdef HAVE_DRIVER_BACKEND
|
|
|
+ DRIVER_hid_free_enumeration(driver_devs);
|
|
|
+#endif
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
- if (libusb_ctx.libhandle) {
|
|
|
- LIBUSB_hid_free_enumeration(usb_devs);
|
|
|
- }
|
|
|
+ LIBUSB_hid_free_enumeration(usb_devs);
|
|
|
+#endif
|
|
|
+#ifdef HAVE_PLATFORM_BACKEND
|
|
|
+ PLATFORM_hid_free_enumeration(raw_devs);
|
|
|
#endif
|
|
|
- return devs;
|
|
|
|
|
|
-#else
|
|
|
- return NULL;
|
|
|
-#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB */
|
|
|
+ return devs;
|
|
|
}
|
|
|
|
|
|
void SDL_hid_free_enumeration(struct SDL_hid_device_info *devs)
|