SDL: Initial HIDAPI driver support for the PS3 controller

From b6f96b69aad62dc4538b8ca4ba5906017108cb55 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 23 Aug 2022 22:45:37 -0700
Subject: [PATCH] Initial HIDAPI driver support for the PS3 controller

---
 include/SDL_hints.h                        | 11 +++++++++++
 src/hidapi/libusb/hid.c                    | 23 ++++++++++++++++++++--
 src/joystick/hidapi/SDL_hidapijoystick.c   |  3 +++
 src/joystick/hidapi/SDL_hidapijoystick_c.h |  2 ++
 src/joystick/usb_ids.h                     |  1 +
 5 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 738f55044b0..6f2823572d5 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -705,6 +705,17 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_HIDAPI_SHIELD "SDL_JOYSTICK_HIDAPI_SHIELD"
 
+/**
+ *  \brief  A variable controlling whether the HIDAPI driver for PS3 controllers should be used.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - HIDAPI driver is not used
+ *    "1"       - HIDAPI driver is used
+ *
+ *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_PS3 "SDL_JOYSTICK_HIDAPI_PS3"
+
 /**
  *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
  *
diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c
index dbcd4fa3bdf..c740be5b6a8 100644
--- a/src/hidapi/libusb/hid.c
+++ b/src/hidapi/libusb/hid.c
@@ -173,6 +173,10 @@ struct hid_device_ {
 	int transfer_loop_finished;
 	struct libusb_transfer *transfer;
 
+	/* Quirks */
+	int skip_output_report_id;
+	int no_output_reports_on_intr_ep;
+
 	/* List of received input reports. */
 	struct input_report *input_reports;
 };
@@ -1144,6 +1148,19 @@ static void init_xboxone(libusb_device_handle *device_handle, unsigned short idV
 	}
 }
 
+static void calculate_device_quirks(hid_device *dev, unsigned short idVendor, unsigned short idProduct)
+{
+	static const int VENDOR_SONY = 0x054c;
+	static const int PRODUCT_PS3_CONTROLLER = 0x0268;
+	static const int PRODUCT_NAVIGATION_CONTROLLER = 0x042f;
+
+	if (idVendor == VENDOR_SONY &&
+	    (idProduct == PRODUCT_PS3_CONTROLLER || idProduct == PRODUCT_NAVIGATION_CONTROLLER)) {
+		dev->skip_output_report_id = 1;
+		dev->no_output_reports_on_intr_ep = 1;
+	}
+}
+
 hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 {
 	hid_device *dev = NULL;
@@ -1269,6 +1286,8 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
 							}
 						}
 
+						calculate_device_quirks(dev, desc.idVendor, desc.idProduct);
+
 						dev->thread = SDL_CreateThread(read_thread, NULL, dev);
 
 						/* Wait here for the read thread to be initialized. */
@@ -1301,11 +1320,11 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t
 {
 	int res;
 
-	if (dev->output_endpoint <= 0) {
+	if (dev->output_endpoint <= 0 || dev->no_output_reports_on_intr_ep) {
 		int report_number = data[0];
 		int skipped_report_id = 0;
 
-		if (report_number == 0x0) {
+		if (report_number == 0x0 || dev->skip_output_report_id) {
 			data++;
 			length--;
 			skipped_report_id = 1;
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index a7baee6348c..35068714993 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -52,6 +52,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
 #ifdef SDL_JOYSTICK_HIDAPI_SHIELD
     &SDL_HIDAPI_DriverShield,
 #endif
+#ifdef SDL_JOYSTICK_HIDAPI_PS3
+    &SDL_HIDAPI_DriverPS3,
+#endif
 #ifdef SDL_JOYSTICK_HIDAPI_PS4
     &SDL_HIDAPI_DriverPS4,
 #endif
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index 3975e0b4f9a..fbf21acd27c 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -34,6 +34,7 @@
 /* This is the full set of HIDAPI drivers available */
 #define SDL_JOYSTICK_HIDAPI_GAMECUBE
 #define SDL_JOYSTICK_HIDAPI_LUNA
+#define SDL_JOYSTICK_HIDAPI_PS3
 #define SDL_JOYSTICK_HIDAPI_PS4
 #define SDL_JOYSTICK_HIDAPI_PS5
 #define SDL_JOYSTICK_HIDAPI_STADIA
@@ -125,6 +126,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic;
+extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield;
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index a22a2865259..f1cd185dca6 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -57,6 +57,7 @@
 #define USB_PRODUCT_RAZER_PANTHERA                          0x0401
 #define USB_PRODUCT_RAZER_PANTHERA_EVO                      0x1008
 #define USB_PRODUCT_RAZER_ATROX                             0x0a00
+#define USB_PRODUCT_SONY_DS3                                0x0268
 #define USB_PRODUCT_SONY_DS4                                0x05c4
 #define USB_PRODUCT_SONY_DS4_DONGLE                         0x0ba0
 #define USB_PRODUCT_SONY_DS4_SLIM                           0x09cc