From 7fd46ec581d45ec3fea3fcfe226bbc2ae824fc7c Mon Sep 17 00:00:00 2001
From: Francisco Javier Trujillo Mata <[EMAIL REDACTED]>
Date: Sat, 18 Jun 2022 17:40:53 +0200
Subject: [PATCH] Initial PS2_Joystick implementation
---
CMakeLists.txt | 8 +-
include/SDL_config.h.cmake | 1 +
src/joystick/SDL_gamecontrollerdb.h | 3 +
src/joystick/SDL_joystick.c | 3 +
src/joystick/SDL_sysjoystick.h | 3 +-
src/joystick/ps2/SDL_sysjoystick.c | 348 ++++++++++++++++++++++++++++
6 files changed, 364 insertions(+), 2 deletions(-)
create mode 100644 src/joystick/ps2/SDL_sysjoystick.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b82f735506c..1f42cf5f7c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2539,7 +2539,7 @@ elseif(PSP)
endif(NOT SDL2_DISABLE_SDL2MAIN)
elseif(PS2)
- list(APPEND EXTRA_CFLAGS "-DPS2" "-D__PS2__" "-I${PS2SDK}/ports/include")
+ list(APPEND EXTRA_CFLAGS "-DPS2" "-D__PS2__" "-I$ENV{PS2SDK}/ports/include")
file(GLOB PS2_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/ps2/*.c)
set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${PS2_MAIN_SOURCES})
@@ -2550,6 +2550,12 @@ elseif(PS2)
list(APPEND SOURCE_FILES ${PS2_FILESYSTEM_SOURCES})
set(HAVE_SDL_FILESYSTEM TRUE)
endif()
+ if(SDL_JOYSTICK)
+ set(SDL_JOYSTICK_PS2 1)
+ file(GLOB PS2_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/ps2/*.c)
+ list(APPEND SOURCE_FILES ${PS2_JOYSTICK_SOURCES})
+ set(HAVE_SDL_JOYSTICK TRUE)
+ endif()
if(SDL_THREADS)
set(SDL_THREAD_PS2 1)
file(GLOB PS2_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c ${SDL2_SOURCE_DIR}/src/thread/ps2/*.c)
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 9cc18ab95c1..129e808d2ab 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -348,6 +348,7 @@
#cmakedefine SDL_JOYSTICK_VIRTUAL @SDL_JOYSTICK_VIRTUAL@
#cmakedefine SDL_JOYSTICK_VITA @SDL_JOYSTICK_VITA@
#cmakedefine SDL_JOYSTICK_PSP @SDL_JOYSTICK_PSP@
+#cmakedefine SDL_JOYSTICK_PS2 @SDL_JOYSTICK_PS2@
#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 9266c5165fc..aa9d35780de 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -913,6 +913,9 @@ static const char *s_ControllerMappings [] =
#endif
#if defined(SDL_JOYSTICK_PSP)
"505350206275696c74696e206a6f7970,PSP builtin joypad,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
+#endif
+#if defined(SDL_JOYSTICK_PS2)
+ "50533220436f6e74726f6c6c65720000,PS2 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,leftstick:b1,rightstick:b2,",
#endif
"hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
NULL
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 32f03fffb76..bfb20464239 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -89,6 +89,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
#ifdef SDL_JOYSTICK_OS2
&SDL_OS2_JoystickDriver,
#endif
+#ifdef SDL_JOYSTICK_PS2
+ &SDL_PS2_JoystickDriver,
+#endif
#ifdef SDL_JOYSTICK_PSP
&SDL_PSP_JoystickDriver,
#endif
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 6fd82bdce14..4215f4a514a 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -155,7 +155,7 @@ typedef struct _SDL_JoystickDriver
/* Function to get the player index of a joystick */
int (*GetDevicePlayerIndex)(int device_index);
- /* Function to get the player index of a joystick */
+ /* Function to set the player index of a joystick */
void (*SetDevicePlayerIndex)(int device_index, int player_index);
/* Function to return the stable GUID for a plugged in device */
@@ -226,6 +226,7 @@ extern SDL_JoystickDriver SDL_WGI_JoystickDriver;
extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
extern SDL_JoystickDriver SDL_WINMM_JoystickDriver;
extern SDL_JoystickDriver SDL_OS2_JoystickDriver;
+extern SDL_JoystickDriver SDL_PS2_JoystickDriver;
extern SDL_JoystickDriver SDL_PSP_JoystickDriver;
extern SDL_JoystickDriver SDL_VITA_JoystickDriver;
diff --git a/src/joystick/ps2/SDL_sysjoystick.c b/src/joystick/ps2/SDL_sysjoystick.c
new file mode 100644
index 00000000000..d30b3c1b1bb
--- /dev/null
+++ b/src/joystick/ps2/SDL_sysjoystick.c
@@ -0,0 +1,348 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_JOYSTICK_PS2
+
+/* This is the PS2 implementation of the SDL joystick API */
+#include <libmtap.h>
+#include <libpad.h>
+#include <ps2_joystick_driver.h>
+
+#include <stdio.h> /* For the definition of NULL */
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "../SDL_sysjoystick.h"
+#include "../SDL_joystick_c.h"
+
+#include "SDL_events.h"
+#include "SDL_error.h"
+
+#define PS2_MAX_PORT 2 /* each ps2 has 2 ports */
+#define PS2_MAX_SLOT 4 /* maximum - 4 slots in one multitap */
+#define MAX_CONTROLLERS (PS2_MAX_PORT * PS2_MAX_SLOT)
+#define PS2_ANALOG_STICKS 2
+#define PS2_ANALOG_AXIS 2
+#define PS2_BUTTONS 16
+#define PS2_TOTAL_AXIS (PS2_ANALOG_STICKS * PS2_ANALOG_AXIS)
+
+struct JoyInfo {
+ uint8_t padBuf[256];
+ uint16_t btns;
+ uint8_t analog_state[PS2_TOTAL_AXIS];
+ uint8_t port;
+ uint8_t slot;
+ int8_t rumble_ready;
+} __attribute__ ((aligned (64)));
+
+static uint8_t enabled_pads = 0;
+static struct JoyInfo joyInfo[MAX_CONTROLLERS];
+
+static inline int16_t convert_u8_to_s16(uint8_t val)
+{
+ if (val == 0)
+ return -0x7fff;
+ return val * 0x0101 - 0x8000;
+}
+
+static inline uint8_t rumble_status(uint8_t index)
+{
+ char actAlign[6];
+ int res;
+ struct JoyInfo *info = &joyInfo[index];
+
+ if (info->rumble_ready == 0) {
+ actAlign[0] = 0;
+ actAlign[1] = 1;
+ actAlign[2] = 0xff;
+ actAlign[3] = 0xff;
+ actAlign[4] = 0xff;
+ actAlign[5] = 0xff;
+
+ res = padSetActAlign(info->port, info->slot, actAlign);
+ info->rumble_ready = res <= 0 ? -1 : 1;
+ }
+
+ return info->rumble_ready == 1;
+}
+
+/* Function to scan the system for joysticks.
+* Joystick 0 should be the system default joystick.
+* This function should return 0, or -1 on an unrecoverable error.
+*/
+static int PS2_JoystickInit(void)
+{
+ uint32_t port = 0;
+ uint32_t slot = 0;
+
+ if(init_joystick_driver(true) < 0)
+ return -1;
+
+ for (port = 0; port < PS2_MAX_PORT; port++)
+ mtapPortOpen(port);
+ /* it can fail - we dont care, we will check it more strictly when padPortOpen */
+
+ for (slot = 0; slot < PS2_MAX_SLOT; slot++) {
+ for (port = 0; port < PS2_MAX_PORT; port++) {
+ /* 2 main controller ports acts the same with and without multitap
+ Port 0,0 -> Connector 1 - the same as Port 0
+ Port 1,0 -> Connector 2 - the same as Port 1
+ Port 0,1 -> Connector 3
+ Port 1,1 -> Connector 4
+ Port 0,2 -> Connector 5
+ Port 1,2 -> Connector 6
+ Port 0,3 -> Connector 7
+ Port 1,3 -> Connector 8
+ */
+
+ struct JoyInfo *info = &joyInfo[enabled_pads];
+ if(padPortOpen(port, slot, (void *)info->padBuf) > 0) {
+ info->port = (uint8_t)port;
+ info->slot = (uint8_t)slot;
+ enabled_pads++;
+ }
+ }
+ }
+
+ return enabled_pads > 0 ? 0 : -1;
+}
+
+/* Function to return the number of joystick devices plugged in right now */
+static int PS2_JoystickGetCount()
+{
+ return (int)enabled_pads;
+}
+
+/* Function to cause any queued joystick insertions to be processed */
+static void PS2_JoystickDetect()
+{
+}
+
+/* Function to get the device-dependent name of a joystick */
+static const char *PS2_JoystickGetDeviceName(int index)
+{
+ if (index >= 0 && index < enabled_pads)
+ return "PS2 Controller";
+
+ SDL_SetError("No joystick available with that index");
+ return NULL;
+}
+
+/* Function to get the device-dependent path of a joystick */
+static const char *PS2_JoystickGetDevicePath(int index)
+{
+ return NULL;
+}
+
+/* Function to get the player index of a joystick */
+static int PS2_JoystickGetDevicePlayerIndex(int device_index)
+{
+ return -1;
+}
+
+/* Function to set the player index of a joystick */
+static void PS2_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
+/* Function to return the stable GUID for a plugged in device */
+static SDL_JoystickGUID PS2_JoystickGetDeviceGUID( int device_index )
+{
+ SDL_JoystickGUID guid;
+ /* the GUID is just the first 16 chars of the name for now */
+ const char *name = PS2_JoystickGetDeviceName(device_index);
+ SDL_zero(guid);
+ SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name)));
+ return guid;
+}
+
+/* Function to get the current instance id of the joystick located at device_index */
+static SDL_JoystickID PS2_JoystickGetDeviceInstanceID(int device_index)
+{
+ return device_index;
+}
+
+/* Function to open a joystick for use.
+ The joystick to open is specified by the device index.
+ This should fill the nbuttons and naxes fields of the joystick structure.
+ It returns 0, or -1 if there is an error.
+*/
+static int PS2_JoystickOpen(SDL_Joystick *joystick, int device_index)
+{
+ joystick->nbuttons = PS2_BUTTONS;
+ joystick->naxes = PS2_TOTAL_AXIS;
+ joystick->nhats = 0;
+ joystick->instance_id = device_index;
+
+ return 0;
+}
+
+/* Rumble functionality */
+static int PS2_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+{
+ char actAlign[6];
+ int res;
+ int index = joystick->instance_id;
+ struct JoyInfo *info = &joyInfo[index];
+
+ if (!rumble_status(index)) {
+ return -1;
+ }
+
+ // Initial value
+ actAlign[0] = low_frequency_rumble >> 8; // Enable small engine
+ actAlign[1] = high_frequency_rumble >> 8; // Enable big engine
+ actAlign[2] = 0xff;
+ actAlign[3] = 0xff;
+ actAlign[4] = 0xff;
+ actAlign[5] = 0xff;
+
+ res = padSetActDirect(info->port, info->slot, actAlign);
+ return res == 1 ? 0 : -1;
+}
+
+/* Rumble functionality */
+static int PS2_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right)
+{
+ return -1;
+}
+
+/* Capability detection */
+static Uint32 PS2_JoystickGetCapabilities(SDL_Joystick *joystick)
+{
+ return SDL_JOYCAP_RUMBLE;
+}
+
+/* LED functionality */
+static int PS2_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+ return -1;
+}
+
+/* General effects */
+static int PS2_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ return -1;
+}
+
+/* Sensor functionality */
+static int PS2_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
+{
+ return -1;
+}
+
+/* Function to update the state of a joystick - called as a device poll.
+* This function shouldn't update the joystick structure directly,
+* but instead should call SDL_PrivateJoystick*() to deliver events
+* and update joystick device state.
+*/
+static void PS2_JoystickUpdate(SDL_Joystick *joystick)
+{
+ uint8_t i;
+ uint8_t previous_axis, current_axis;
+ uint16_t mask, previous, current;
+ struct padButtonStatus buttons;
+ uint8_t all_axis[PS2_TOTAL_AXIS];
+ int index = joystick->instance_id;
+ struct JoyInfo *info = &joyInfo[index];
+ int state = padGetState(info->port, info->slot);
+
+ if (state != PAD_STATE_DISCONN || state != PAD_STATE_EXECCMD || state != PAD_STATE_ERROR) {
+ int ret = padRead(info->port, info->slot, &buttons); /* port, slot, buttons */
+ if (ret != 0) {
+ /* Buttons */
+ int32_t pressed_buttons = 0xffff ^ buttons.btns;;
+ if (info->btns != pressed_buttons) {
+ for (i = 0; i < PS2_BUTTONS; i++) {
+ mask = (1 << i);
+ previous = info->btns & mask;
+ current = pressed_buttons & mask;
+ if (previous != current)
+ SDL_PrivateJoystickButton(joystick, i, current ? SDL_PRESSED : SDL_RELEASED);
+ }
+ }
+ info->btns = pressed_buttons;
+
+ /* Analog */
+ all_axis[0] = buttons.ljoy_h;
+ all_axis[1] = buttons.ljoy_v;
+ all_axis[2] = buttons.rjoy_h;
+ all_axis[3] = buttons.rjoy_v;
+
+ for (i = 0; i < PS2_TOTAL_AXIS; i++) {
+ previous_axis = info->analog_state[i];
+ current_axis = all_axis[i];
+ if (previous_axis != current_axis)
+ SDL_PrivateJoystickAxis(joystick, i, convert_u8_to_s16(current_axis));
+
+ info->analog_state[i] = current_axis;
+ }
+ }
+ }
+}
+
+/* Function to close a joystick after use */
+static void PS2_JoystickClose(SDL_Joystick *joystick)
+{
+ int index = joystick->instance_id;
+ struct JoyInfo *info = &joyInfo[index];
+ padPortClose(info->port, info->slot);
+}
+
+/* Function to perform any system-specific joystick related cleanup */
+static void PS2_JoystickQuit(void)
+{
+ deinit_joystick_driver(true);
+}
+
+static SDL_bool PS2_GetGamepadMapping(int device_index, SDL_GamepadMapping * out)
+{
+ return SDL_FALSE;
+}
+
+SDL_JoystickDriver SDL_PS2_JoystickDriver =
+{
+ PS2_JoystickInit,
+ PS2_JoystickGetCount,
+ PS2_JoystickDetect,
+ PS2_JoystickGetDeviceName,
+ PS2_JoystickGetDevicePath,
+ PS2_JoystickGetDevicePlayerIndex,
+ PS2_JoystickSetDevicePlayerIndex,
+ PS2_JoystickGetDeviceGUID,
+ PS2_JoystickGetDeviceInstanceID,
+ PS2_JoystickOpen,
+ PS2_JoystickRumble,
+ PS2_JoystickRumbleTriggers,
+ PS2_JoystickGetCapabilities,
+ PS2_JoystickSetLED,
+ PS2_JoystickSendEffect,
+ PS2_JoystickSetSensorsEnabled,
+ PS2_JoystickUpdate,
+ PS2_JoystickClose,
+ PS2_JoystickQuit,
+ PS2_GetGamepadMapping,
+};
+
+#endif /* SDL_JOYSTICK_PS2 */
+
+/* vi: set ts=4 sw=4 expandtab: */