From 7fd46ec581d45ec3fea3fcfe226bbc2ae824fc7c Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata 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 b82f73550..1f42cf5f7 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 9cc18ab95..129e808d2 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 9266c5165..aa9d35780 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 32f03fffb..bfb204642 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 6fd82bdce..4215f4a51 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 000000000..d30b3c1b1 --- /dev/null +++ b/src/joystick/ps2/SDL_sysjoystick.c @@ -0,0 +1,348 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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 +#include +#include + +#include /* For the definition of NULL */ +#include +#include + +#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: */