SDL: Added a function to get the controller firmware version

From 423141bfcade1bcb7b160167f80a2049196e281c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 3 Jun 2022 18:49:41 -0700
Subject: [PATCH] Added a function to get the controller firmware version

---
 include/SDL_gamecontroller.h      | 12 ++++++++++++
 include/SDL_joystick.h            | 12 ++++++++++++
 src/dynapi/SDL2.exports           |  2 ++
 src/dynapi/SDL_dynapi_overrides.h |  2 ++
 src/dynapi/SDL_dynapi_procs.h     |  2 ++
 src/joystick/SDL_gamecontroller.c |  6 ++++++
 src/joystick/SDL_joystick.c       |  8 ++++++++
 src/joystick/SDL_sysjoystick.h    |  1 +
 8 files changed, 45 insertions(+)

diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index 6c2c5255854..0f3ce583a66 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -493,6 +493,18 @@ extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetProduct(SDL_GameController *
  */
 extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller);
 
+/**
+ * Get the firmware version of an opened controller, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param gamecontroller the game controller object to query.
+ * \return the controller firmware version, or zero if unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller);
+
 /**
  * Get the serial number of an opened controller, if available.
  *
diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h
index f10689f5677..43dd3bfd9ac 100644
--- a/include/SDL_joystick.h
+++ b/include/SDL_joystick.h
@@ -574,6 +574,18 @@ extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProduct(SDL_Joystick *joystick);
  */
 extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProductVersion(SDL_Joystick *joystick);
 
+/**
+ * Get the firmware version of an opened joystick, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
+ * \returns the firmware version of the selected joystick, or 0 if unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetFirmwareVersion(SDL_Joystick *joystick);
+
 /**
  * Get the serial number of an opened joystick, if available.
  *
diff --git a/src/dynapi/SDL2.exports b/src/dynapi/SDL2.exports
index 3d09d110825..9c6dac42f56 100644
--- a/src/dynapi/SDL2.exports
+++ b/src/dynapi/SDL2.exports
@@ -841,3 +841,5 @@
 ++'_SDL_JoystickPathForIndex'.'SDL2.dll'.'SDL_JoystickPathForIndex'
 ++'_SDL_JoystickPath'.'SDL2.dll'.'SDL_JoystickPath'
 ++'_SDL_JoystickAttachVirtualEx'.'SDL2.dll'.'SDL_JoystickAttachVirtualEx'
+++'_SDL_GameControllerGetFirmwareVersion'.'SDL2.dll'.'SDL_GameControllerGetFirmwareVersion'
+++'_SDL_JoystickGetFirmwareVersion'.'SDL2.dll'.'SDL_JoystickGetFirmwareVersion'
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index c756c38413a..3e4c2588af7 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -867,3 +867,5 @@
 #define SDL_JoystickPathForIndex SDL_JoystickPathForIndex_REAL
 #define SDL_JoystickPath SDL_JoystickPath_REAL
 #define SDL_JoystickAttachVirtualEx SDL_JoystickAttachVirtualEx_REAL
+#define SDL_GameControllerGetFirmwareVersion SDL_GameControllerGetFirmwareVersion_REAL
+#define SDL_JoystickGetFirmwareVersion SDL_JoystickGetFirmwareVersion_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index c14e7a15f1e..f3164760c3f 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -942,3 +942,5 @@ SDL_DYNAPI_PROC(const char*,SDL_GameControllerPath,(SDL_GameController *a),(a),r
 SDL_DYNAPI_PROC(const char*,SDL_JoystickPathForIndex,(int a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_JoystickPath,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_JoystickAttachVirtualEx,(const SDL_VirtualJoystickDesc *a),(a),return)
+SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetFirmwareVersion,(SDL_GameController *a),(a),return)
+SDL_DYNAPI_PROC(Uint16,SDL_JoystickGetFirmwareVersion,(SDL_Joystick *a),(a),return)
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 49053c6656e..2cb51726308 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -2360,6 +2360,12 @@ SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller)
     return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller));
 }
 
+Uint16
+SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller)
+{
+    return SDL_JoystickGetFirmwareVersion(SDL_GameControllerGetJoystick(gamecontroller));
+}
+
 const char *
 SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
 {
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 362c515709e..ae4f5dc9b87 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -2702,6 +2702,14 @@ Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
     return version;
 }
 
+Uint16 SDL_JoystickGetFirmwareVersion(SDL_Joystick *joystick)
+{
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return 0;
+    }
+    return joystick->firmware_version;
+}
+
 const char *SDL_JoystickGetSerial(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 04b6b7a0c91..6fd82bdce14 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -68,6 +68,7 @@ struct _SDL_Joystick
     char *path;                 /* Joystick path - system dependent */
     char *serial;               /* Joystick serial */
     SDL_JoystickGUID guid;      /* Joystick guid */
+    Uint16 firmware_version;    /* Firmware version, if available */
 
     int naxes;                  /* Number of axis controls on the joystick */
     SDL_JoystickAxisInfo *axes;