SDL: Update the SDL HIDAPI API to match upstream hidapi 0.14.0

From af45ae7296ad608b8ef541e40ab5c5b0f202a159 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 24 May 2023 15:16:49 -0700
Subject: [PATCH] Update the SDL HIDAPI API to match upstream hidapi 0.14.0

---
 include/SDL3/SDL_hidapi.h                | 94 +++++++++++++++++++++---
 src/dynapi/SDL_dynapi.sym                |  3 +
 src/dynapi/SDL_dynapi_overrides.h        |  3 +
 src/dynapi/SDL_dynapi_procs.h            |  5 +-
 src/hidapi/SDL_hidapi.c                  | 92 +++++++++++++++++++----
 src/joystick/hidapi/SDL_hidapijoystick.c |  4 +-
 6 files changed, 176 insertions(+), 25 deletions(-)

diff --git a/include/SDL3/SDL_hidapi.h b/include/SDL3/SDL_hidapi.h
index 987621b6abd7..87673255e6ae 100644
--- a/include/SDL3/SDL_hidapi.h
+++ b/include/SDL3/SDL_hidapi.h
@@ -76,6 +76,37 @@ extern "C" {
 struct SDL_hid_device_;
 typedef struct SDL_hid_device_ SDL_hid_device; /**< opaque hidapi structure */
 
+/**
+ *  \brief HID underlying bus types.
+ */
+typedef enum {
+    /** Unknown bus type */
+    SDL_HID_API_BUS_UNKNOWN = 0x00,
+
+    /** USB bus
+       Specifications:
+       https://usb.org/hid */
+    SDL_HID_API_BUS_USB = 0x01,
+
+    /** Bluetooth or Bluetooth LE bus
+       Specifications:
+       https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
+       https://www.bluetooth.com/specifications/specs/hid-service-1-0/
+       https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile-1-0/ */
+    SDL_HID_API_BUS_BLUETOOTH = 0x02,
+
+    /** I2C bus
+       Specifications:
+       https://docs.microsoft.com/previous-versions/windows/hardware/design/dn642101(v=vs.85) */
+    SDL_HID_API_BUS_I2C = 0x03,
+
+    /** SPI bus
+       Specifications:
+       https://www.microsoft.com/download/details.aspx?id=103325 */
+    SDL_HID_API_BUS_SPI = 0x04,
+
+} SDL_hid_bus_type;
+
 /** hidapi info structure */
 /**
  *  \brief  Information about a connected HID device
@@ -98,17 +129,17 @@ typedef struct SDL_hid_device_info
     /** Product string */
     wchar_t *product_string;
     /** Usage Page for this Device/Interface
-        (Windows/Mac only). */
+        (Windows/Mac/hidraw only) */
     unsigned short usage_page;
     /** Usage for this Device/Interface
-        (Windows/Mac only).*/
+        (Windows/Mac/hidraw only) */
     unsigned short usage;
     /** The USB interface which this logical device
         represents.
 
-        * Valid on both Linux implementations in all cases.
-        * Valid on the Windows implementation only if the device
-          contains more than one interface. */
+        Valid only if the device is a USB HID device.
+        Set to -1 in all other cases.
+    */
     int interface_number;
 
     /** Additional information about the USB interface.
@@ -117,8 +148,12 @@ typedef struct SDL_hid_device_info
     int interface_subclass;
     int interface_protocol;
 
+    /** Underlying bus type */
+    SDL_hid_bus_type bus_type;
+
     /** Pointer to the next device */
     struct SDL_hid_device_info *next;
+
 } SDL_hid_device_info;
 
 
@@ -187,8 +222,8 @@ extern DECLSPEC Uint32 SDLCALL SDL_hid_device_change_count(void);
  * matches. If `vendor_id` and `product_id` are both set to 0, then all HID
  * devices will be returned.
  *
- * \param vendor_id The Vendor ID (VID) of the types of device to open.
- * \param product_id The Product ID (PID) of the types of device to open.
+ * \param vendor_id The Vendor ID (VID) of the types of device to open, or 0 to match any vendor.
+ * \param product_id The Product ID (PID) of the types of device to open, or 0 to match any product.
  * \returns a pointer to a linked list of type SDL_hid_device_info, containing
  *          information about the HID devices attached to the system, or NULL
  *          in the case of failure. Free this linked list by calling
@@ -237,13 +272,12 @@ extern DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open(unsigned short vendor_id,
  * platform-specific path name can be used (eg: /dev/hidraw0 on Linux).
  *
  * \param path The path name of the device to open
- * \param bExclusive Open device in exclusive mode (Windows only)
  * \returns a pointer to a SDL_hid_device object on success or NULL on
  *          failure.
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open_path(const char *path, int bExclusive /* = false */);
+extern DECLSPEC SDL_hid_device * SDLCALL SDL_hid_open_path(const char *path);
 
 /**
  * Write an Output report to a HID device.
@@ -377,6 +411,28 @@ extern DECLSPEC int SDLCALL SDL_hid_send_feature_report(SDL_hid_device *dev, con
  */
 extern DECLSPEC int SDLCALL SDL_hid_get_feature_report(SDL_hid_device *dev, unsigned char *data, size_t length);
 
+/**
+ * Get an input report from a HID device.
+ *
+ * Set the first byte of `data` to the Report ID of the report to be read.
+ * Make sure to allow space for this extra byte in `data`. Upon return, the
+ * first byte will still contain the Report ID, and the report data will start
+ * in data[1].
+ *
+ * \param dev A device handle returned from SDL_hid_open().
+ * \param data A buffer to put the read data into, including the Report ID.
+ *             Set the first byte of `data` to the Report ID of the report to
+ *             be read, or set it to zero if your device does not use numbered
+ *             reports.
+ * \param length The number of bytes to read, including an extra byte for the
+ *               report ID. The buffer can be longer than the actual report.
+ * \returns the number of bytes read plus one for the report ID (which is
+ *          still in the first byte), or -1 on error.
+ *
+ * \since This function is available since SDL 3.0.0.
+*/
+extern DECLSPEC int SDLCALL SDL_hid_get_input_report(SDL_hid_device *dev, unsigned char *data, size_t length);
+
 /**
  * Close a HID device.
  *
@@ -441,6 +497,26 @@ extern DECLSPEC int SDLCALL SDL_hid_get_serial_number_string(SDL_hid_device *dev
  */
 extern DECLSPEC int SDLCALL SDL_hid_get_indexed_string(SDL_hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
 
+/**
+ * Get the device info from a HID device.
+ *
+ * \param dev A device handle returned from SDL_hid_open().
+ * \returns a pointer to the SDL_hid_device_info for this hid_device, or NULL in the case of failure; call SDL_GetError() for more information. This struct is valid until the device is closed with SDL_hid_close().
+ */
+extern DECLSPEC SDL_hid_device_info * SDLCALL SDL_hid_get_device_info(SDL_hid_device *dev);
+
+/**
+ * Get a report descriptor from a HID device.
+ *
+ * User has to provide a preallocated buffer where descriptor will be copied to. The recommended size for a preallocated buffer is 4096 bytes.
+ *
+ * \param dev A device handle returned from SDL_hid_open().
+ * \param buf The buffer to copy descriptor into.
+ * \param buf_size The size of the buffer in bytes.
+ * \returns the number of bytes actually copied, or -1 on error; call SDL_GetError() for more information.
+ */
+extern DECLSPEC int SDLCALL SDL_hid_get_report_descriptor(SDL_hid_device *dev, unsigned char *buf, size_t buf_size);
+
 /**
  * Start or stop a BLE scan on iOS and tvOS to pair Steam Controllers
  *
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index c306f532f758..4956c8411e84 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -861,6 +861,9 @@ SDL3_0.0.0 {
     SDL_wcstol;
     SDL_swprintf;
     SDL_vswprintf;
+    SDL_hid_get_input_report;
+    SDL_hid_get_device_info;
+    SDL_hid_get_report_descriptor;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 7da9a97e5722..ebd6a45d85a9 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -887,3 +887,6 @@
 #define SDL_wcstol SDL_wcstol_REAL
 #define SDL_swprintf SDL_swprintf_REAL
 #define SDL_vswprintf SDL_vswprintf_REAL
+#define SDL_hid_get_input_report SDL_hid_get_input_report_REAL
+#define SDL_hid_get_device_info SDL_hid_get_device_info_REAL
+#define SDL_hid_get_report_descriptor SDL_hid_get_report_descriptor_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 9722e2169f7e..8d65e1febd87 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -797,7 +797,7 @@ SDL_DYNAPI_PROC(int,SDL_hid_get_product_string,(SDL_hid_device *a, wchar_t *b, s
 SDL_DYNAPI_PROC(int,SDL_hid_get_serial_number_string,(SDL_hid_device *a, wchar_t *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_hid_init,(void),(),return)
 SDL_DYNAPI_PROC(SDL_hid_device*,SDL_hid_open,(unsigned short a, unsigned short b, const wchar_t *c),(a,b,c),return)
-SDL_DYNAPI_PROC(SDL_hid_device*,SDL_hid_open_path,(const char *a, int b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_hid_device*,SDL_hid_open_path,(const char *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_hid_read,(SDL_hid_device *a, unsigned char *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_hid_read_timeout,(SDL_hid_device *a, unsigned char *b, size_t c, int d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(int,SDL_hid_send_feature_report,(SDL_hid_device *a, const unsigned char *b, size_t c),(a,b,c),return)
@@ -932,3 +932,6 @@ SDL_DYNAPI_PROC(float,SDL_GetWindowDisplayScale,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(float,SDL_GetWindowPixelDensity,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_vswprintf,(wchar_t *a, size_t b, const wchar_t *c, va_list d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_hid_get_input_report,(SDL_hid_device *a, unsigned char *b, size_t c),(a,b,c),return)
+SDL_DYNAPI_PROC(SDL_hid_device_info*,SDL_hid_get_device_info,(SDL_hid_device *a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_hid_get_report_descriptor,(SDL_hid_device *a, unsigned char *b, size_t c),(a,b,c),return)
diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c
index d8eefb274238..a15526b8f115 100644
--- a/src/hidapi/SDL_hidapi.c
+++ b/src/hidapi/SDL_hidapi.c
@@ -31,6 +31,9 @@
 
 #include "SDL_hidapi_c.h"
 
+/* Initial type declarations */
+#include "hidapi/hidapi.h"
+
 #ifndef SDL_HIDAPI_DISABLED
 
 #if defined(__WIN32__) || defined(__WINGDK__)
@@ -540,6 +543,7 @@ typedef struct PLATFORM_hid_device_ PLATFORM_hid_device;
 #define hid_get_device_info          PLATFORM_hid_get_device_info
 #define hid_get_feature_report       PLATFORM_hid_get_feature_report
 #define hid_get_indexed_string       PLATFORM_hid_get_indexed_string
+#define hid_get_input_report         PLATFORM_hid_get_input_report
 #define hid_get_manufacturer_string  PLATFORM_hid_get_manufacturer_string
 #define hid_get_product_string       PLATFORM_hid_get_product_string
 #define hid_get_report_descriptor    PLATFORM_hid_get_report_descriptor
@@ -560,7 +564,9 @@ typedef struct PLATFORM_hid_device_ PLATFORM_hid_device;
 #define read_thread                  PLATFORM_read_thread
 #define return_data                  PLATFORM_return_data
 
+/* Allow hidapi.h to be included in the platform implementation */
 #undef HIDAPI_H__
+
 #ifdef __LINUX__
 
 #ifdef SDL_USE_LIBUDEV
@@ -633,6 +639,7 @@ static const SDL_UDEV_Symbols *udev_ctx = NULL;
 #undef hid_get_device_info
 #undef hid_get_feature_report
 #undef hid_get_indexed_string
+#undef hid_get_input_report
 #undef hid_get_manufacturer_string
 #undef hid_get_product_string
 #undef hid_get_report_descriptor
@@ -671,8 +678,10 @@ typedef struct DRIVER_hid_device_ DRIVER_hid_device;
 #define hid_error                    DRIVER_hid_error
 #define hid_exit                     DRIVER_hid_exit
 #define hid_free_enumeration         DRIVER_hid_free_enumeration
+#define hid_get_device_info          DRIVER_hid_device_info
 #define hid_get_feature_report       DRIVER_hid_get_feature_report
 #define hid_get_indexed_string       DRIVER_hid_get_indexed_string
+#define hid_get_input_report         DRIVER_hid_get_input_report
 #define hid_get_manufacturer_string  DRIVER_hid_get_manufacturer_string
 #define hid_get_product_string       DRIVER_hid_get_product_string
 #define hid_get_report_descriptor    DRIVER_hid_get_report_descriptor
@@ -700,8 +709,10 @@ typedef struct DRIVER_hid_device_ DRIVER_hid_device;
 #undef hid_error
 #undef hid_exit
 #undef hid_free_enumeration
+#undef hid_get_device_info
 #undef hid_get_feature_report
 #undef hid_get_indexed_string
+#undef hid_get_input_report
 #undef hid_get_manufacturer_string
 #undef hid_get_product_string
 #undef hid_get_report_descriptor
@@ -824,9 +835,10 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
 #define hid_error                    LIBUSB_hid_error
 #define hid_exit                     LIBUSB_hid_exit
 #define hid_free_enumeration         LIBUSB_hid_free_enumeration
+#define hid_get_device_info          LIBUSB_hid_get_device_info
 #define hid_get_feature_report       LIBUSB_hid_get_feature_report
-#define hid_get_input_report         LIBUSB_hid_get_input_report
 #define hid_get_indexed_string       LIBUSB_hid_get_indexed_string
+#define hid_get_input_report         LIBUSB_hid_get_input_report
 #define hid_get_manufacturer_string  LIBUSB_hid_get_manufacturer_string
 #define hid_get_product_string       LIBUSB_hid_get_product_string
 #define hid_get_report_descriptor    LIBUSB_hid_get_report_descriptor
@@ -900,9 +912,10 @@ static int SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
 #undef hid_error
 #undef hid_exit
 #undef hid_free_enumeration
+#undef hid_get_device_info
 #undef hid_get_feature_report
-#undef hid_get_input_report
 #undef hid_get_indexed_string
+#undef hid_get_input_report
 #undef hid_get_manufacturer_string
 #undef hid_get_product_string
 #undef hid_get_report_descriptor
@@ -935,11 +948,14 @@ struct hidapi_backend
     int (*hid_set_nonblocking)(void *device, int nonblock);
     int (*hid_send_feature_report)(void *device, const unsigned char *data, size_t length);
     int (*hid_get_feature_report)(void *device, unsigned char *data, size_t length);
+    int (*hid_get_input_report)(void *device, unsigned char *data, size_t length);
     void (*hid_close)(void *device);
     int (*hid_get_manufacturer_string)(void *device, wchar_t *string, size_t maxlen);
     int (*hid_get_product_string)(void *device, wchar_t *string, size_t maxlen);
     int (*hid_get_serial_number_string)(void *device, wchar_t *string, size_t maxlen);
     int (*hid_get_indexed_string)(void *device, int string_index, wchar_t *string, size_t maxlen);
+    struct hid_device_info *(*hid_get_device_info)(void *device);
+    int (*hid_get_report_descriptor)(void *device, unsigned char *buf, size_t buf_size);
     const wchar_t *(*hid_error)(void *device);
 };
 
@@ -951,11 +967,14 @@ static const struct hidapi_backend PLATFORM_Backend = {
     (void *)PLATFORM_hid_set_nonblocking,
     (void *)PLATFORM_hid_send_feature_report,
     (void *)PLATFORM_hid_get_feature_report,
+    (void *)PLATFORM_hid_get_input_report,
     (void *)PLATFORM_hid_close,
     (void *)PLATFORM_hid_get_manufacturer_string,
     (void *)PLATFORM_hid_get_product_string,
     (void *)PLATFORM_hid_get_serial_number_string,
     (void *)PLATFORM_hid_get_indexed_string,
+    (void *)PLATFORM_hid_get_device_info,
+    (void *)PLATFORM_hid_get_report_descriptor,
     (void *)PLATFORM_hid_error
 };
 #endif /* HAVE_PLATFORM_BACKEND */
@@ -968,11 +987,14 @@ static const struct hidapi_backend DRIVER_Backend = {
     (void *)DRIVER_hid_set_nonblocking,
     (void *)DRIVER_hid_send_feature_report,
     (void *)DRIVER_hid_get_feature_report,
+    (void *)DRIVER_hid_get_input_report,
     (void *)DRIVER_hid_close,
     (void *)DRIVER_hid_get_manufacturer_string,
     (void *)DRIVER_hid_get_product_string,
     (void *)DRIVER_hid_get_serial_number_string,
     (void *)DRIVER_hid_get_indexed_string,
+    (void *)DRIVER_hid_get_device_info,
+    (void *)DRIVER_hid_get_report_descriptor,
     (void *)DRIVER_hid_error
 };
 #endif /* HAVE_DRIVER_BACKEND */
@@ -985,11 +1007,14 @@ static const struct hidapi_backend LIBUSB_Backend = {
     (void *)LIBUSB_hid_set_nonblocking,
     (void *)LIBUSB_hid_send_feature_report,
     (void *)LIBUSB_hid_get_feature_report,
+    (void *)LIBUSB_hid_get_input_report,
     (void *)LIBUSB_hid_close,
     (void *)LIBUSB_hid_get_manufacturer_string,
     (void *)LIBUSB_hid_get_product_string,
     (void *)LIBUSB_hid_get_serial_number_string,
     (void *)LIBUSB_hid_get_indexed_string,
+    (void *)LIBUSB_hid_get_device_info,
+    (void *)LIBUSB_hid_get_report_descriptor,
     (void *)LIBUSB_hid_error
 };
 #endif /* HAVE_LIBUSB */
@@ -999,6 +1024,7 @@ struct SDL_hid_device_
     const void *magic;
     void *device;
     const struct hidapi_backend *backend;
+    SDL_hid_device_info info;
 };
 static char device_magic;
 
@@ -1010,15 +1036,19 @@ static SDL_hid_device *CreateHIDDeviceWrapper(void *device, const struct hidapi_
     wrapper->magic = &device_magic;
     wrapper->device = device;
     wrapper->backend = backend;
+    SDL_zero(wrapper->info);
     return wrapper;
 }
 
 #endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB */
 
-static void
-DeleteHIDDeviceWrapper(SDL_hid_device *device)
+static void DeleteHIDDeviceWrapper(SDL_hid_device *device)
 {
     device->magic = NULL;
+    SDL_free(device->info.path);
+    SDL_free(device->info.serial_number);
+    SDL_free(device->info.manufacturer_string);
+    SDL_free(device->info.product_string);
     SDL_free(device);
 }
 
@@ -1028,9 +1058,6 @@ DeleteHIDDeviceWrapper(SDL_hid_device *device)
         return retval;                               \
     }
 
-#ifndef SDL_HIDAPI_DISABLED
-#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB)
-
 #define COPY_IF_EXISTS(var)                \
     if (pSrc->var != NULL) {               \
         pDst->var = SDL_strdup(pSrc->var); \
@@ -1044,8 +1071,7 @@ DeleteHIDDeviceWrapper(SDL_hid_device *device)
         pDst->var = NULL;                  \
     }
 
-static void
-CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_device_info *pDst)
+static void CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_device_info *pDst)
 {
     COPY_IF_EXISTS(path)
     pDst->vendor_id = pSrc->vendor_id;
@@ -1060,15 +1086,13 @@ CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_device_info *pDst
     pDst->interface_class = pSrc->interface_class;
     pDst->interface_subclass = pSrc->interface_subclass;
     pDst->interface_protocol = pSrc->interface_protocol;
+    pDst->bus_type = (SDL_hid_bus_type)pSrc->bus_type;
     pDst->next = NULL;
 }
 
 #undef COPY_IF_EXISTS
 #undef WCOPY_IF_EXISTS
 
-#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB */
-#endif /* !SDL_HIDAPI_DISABLED */
-
 static int SDL_hidapi_refcount = 0;
 
 static void SDL_SetHIDAPIError(const wchar_t *error)
@@ -1451,7 +1475,7 @@ SDL_hid_device *SDL_hid_open(unsigned short vendor_id, unsigned short product_id
     return NULL;
 }
 
-SDL_hid_device *SDL_hid_open_path(const char *path, int bExclusive /* = false */)
+SDL_hid_device *SDL_hid_open_path(const char *path)
 {
 #if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB)
     void *pDevice = NULL;
@@ -1568,6 +1592,19 @@ int SDL_hid_get_feature_report(SDL_hid_device *device, unsigned char *data, size
     return result;
 }
 
+int SDL_hid_get_input_report(SDL_hid_device *device, unsigned char *data, size_t length)
+{
+    int result;
+
+    CHECK_DEVICE_MAGIC(device, -1);
+
+    result = device->backend->hid_get_input_report(device->device, data, length);
+    if (result < 0) {
+        SDL_SetHIDAPIError(device->backend->hid_error(device->device));
+    }
+    return result;
+}
+
 int SDL_hid_close(SDL_hid_device *device)
 {
     CHECK_DEVICE_MAGIC(device, -1);
@@ -1629,6 +1666,35 @@ int SDL_hid_get_indexed_string(SDL_hid_device *device, int string_index, wchar_t
     return result;
 }
 
+SDL_hid_device_info *SDL_hid_get_device_info(SDL_hid_device *device)
+{
+    struct hid_device_info *info;
+
+    CHECK_DEVICE_MAGIC(device, NULL);
+
+    info = device->backend->hid_get_device_info(device->device);
+    if (info) {
+        CopyHIDDeviceInfo(info, &device->info);
+        return &device->info;
+    } else {
+        SDL_SetHIDAPIError(device->backend->hid_error(device->device));
+        return NULL;
+    }
+}
+
+int SDL_hid_get_report_descriptor(SDL_hid_device *device, unsigned char *buf, size_t buf_size)
+{
+    int result;
+
+    CHECK_DEVICE_MAGIC(device, -1);
+
+    result = device->backend->hid_get_report_descriptor(device->device, buf, buf_size);
+    if (result < 0) {
+        SDL_SetHIDAPIError(device->backend->hid_error(device->device));
+    }
+    return result;
+}
+
 void SDL_hid_ble_scan(SDL_bool active)
 {
 #if !defined(SDL_HIDAPI_DISABLED) && (defined(__IOS__) || defined(__TVOS__))
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index daea81cd56c7..a7ae20eacf34 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -459,7 +459,7 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, SDL_bool *remove
                     SDL_UnlockJoysticks();
                 }
 
-                dev = SDL_hid_open_path(path, 0);
+                dev = SDL_hid_open_path(path);
 
                 while (lock_count > 0) {
                     --lock_count;
@@ -490,7 +490,7 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, SDL_bool *remove
              *
              * See https://github.com/libsdl-org/SDL/issues/7304 for details.
              */
-            dev = SDL_hid_open_path(device->path, 0);
+            dev = SDL_hid_open_path(device->path);
 #endif
 
             if (dev == NULL) {