mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-07 07:00:48 +00:00
Add DSU support for more platforms
Extended DSU support to additional platforms including QNX, RISC OS, PlayStation Vita, PSP, PS2, and Nintendo 3DS. Updated CMakeLists.txt to handle platform-specific dependencies and added platform-specific socket handling, initialization, and cleanup in SDL_dsujoystick.c. Introduced wrappers for network functions and improved error handling for these platforms.
This commit is contained in:
parent
345b961493
commit
db33ef9e10
2 changed files with 201 additions and 26 deletions
|
|
@ -1377,7 +1377,13 @@ if(SDL_JOYSTICK)
|
|||
endif()
|
||||
|
||||
# DSU (DualShock UDP) client support
|
||||
if(SDL_DSU_JOYSTICK AND NOT EMSCRIPTEN AND (WINDOWS OR LINUX OR ANDROID OR HAIKU OR FREEBSD OR NETBSD OR OPENBSD OR MACOS))
|
||||
# Supported on platforms with UDP socket support (BSD sockets or WinSock)
|
||||
# Note: Some of these platforms haven't been fully tested yet but should work in theory
|
||||
if(SDL_DSU_JOYSTICK AND NOT EMSCRIPTEN AND
|
||||
(WINDOWS OR LINUX OR ANDROID OR HAIKU OR FREEBSD OR NETBSD OR OPENBSD OR
|
||||
MACOS OR IOS OR TVOS OR VISIONOS OR WATCHOS OR
|
||||
QNX OR RISCOS OR
|
||||
VITA OR PSP OR PS2 OR N3DS))
|
||||
set(SDL_JOYSTICK_DSU 1)
|
||||
sdl_glob_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/joystick/dsu/*.c"
|
||||
|
|
@ -1389,6 +1395,30 @@ if(SDL_JOYSTICK)
|
|||
sdl_link_dependency(dsu LIBS ws2_32)
|
||||
elseif(HAIKU)
|
||||
sdl_link_dependency(dsu LIBS network)
|
||||
elseif(QNX)
|
||||
# QNX needs socket library
|
||||
sdl_link_dependency(dsu LIBS socket)
|
||||
elseif(VITA)
|
||||
# PlayStation Vita networking libraries
|
||||
sdl_link_dependency(dsu LIBS
|
||||
SceNet_stub
|
||||
SceNetCtl_stub
|
||||
)
|
||||
elseif(PSP)
|
||||
# PSP networking libraries
|
||||
sdl_link_dependency(dsu LIBS
|
||||
pspnet
|
||||
pspnet_inet
|
||||
pspnet_resolver
|
||||
)
|
||||
elseif(PS2)
|
||||
# PlayStation 2 uses ps2sdk's lwIP
|
||||
sdl_link_dependency(dsu LIBS
|
||||
ps2ip
|
||||
)
|
||||
elseif(N3DS)
|
||||
# Nintendo 3DS networking libraries (if available)
|
||||
sdl_link_dependency(dsu LIBS ctru)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -54,19 +54,84 @@ typedef int socklen_t;
|
|||
|
||||
/* Platform-specific socket includes */
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* iOS/tvOS/watchOS/visionOS - Same as macOS */
|
||||
#if defined(__APPLE__)
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
/* QNX */
|
||||
#elif defined(__QNXNTO__)
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
/* PlayStation Vita */
|
||||
#elif defined(__VITA__)
|
||||
#include <psp2/net/net.h>
|
||||
#include <psp2/net/netctl.h>
|
||||
#include <psp2/errno.h>
|
||||
#define socklen_t unsigned int
|
||||
#define closesocket sceNetSocketClose
|
||||
#define EAGAIN SCE_NET_EAGAIN
|
||||
#define EWOULDBLOCK SCE_NET_EWOULDBLOCK
|
||||
/* PlayStation Portable */
|
||||
#elif defined(__PSP__)
|
||||
#include <pspnet.h>
|
||||
#include <pspnet_inet.h>
|
||||
#include <pspnet_resolver.h>
|
||||
#include <psperror.h>
|
||||
#define socklen_t unsigned int
|
||||
#define closesocket sceNetInetClose
|
||||
/* Nintendo 3DS */
|
||||
#elif defined(__3DS__)
|
||||
#include <3ds.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#define closesocket closesocket /* 3DS uses closesocket like Windows */
|
||||
/* PlayStation 2 */
|
||||
#elif defined(__PS2__)
|
||||
/* PS2 networking support - requires ps2sdk */
|
||||
#include <ps2ip.h>
|
||||
#include <errno.h>
|
||||
#define socklen_t unsigned int
|
||||
#define closesocket lwip_close
|
||||
/* RISC OS */
|
||||
#elif defined(__riscos__)
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
/* Standard Unix/Linux */
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef __sun
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
#define closesocket close
|
||||
#endif
|
||||
#ifdef __sun
|
||||
#include <sys/filio.h>
|
||||
|
||||
/* Default closesocket if not defined */
|
||||
#ifndef closesocket
|
||||
#define closesocket close
|
||||
#endif
|
||||
#define closesocket close
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
|
@ -121,21 +186,65 @@ struct DSU_Context_t *s_dsu_ctx = NULL;
|
|||
void DSU_RequestControllerInfo(DSU_Context *ctx, Uint8 slot);
|
||||
void DSU_RequestControllerData(DSU_Context *ctx, Uint8 slot);
|
||||
|
||||
/* Platform-specific network function wrappers */
|
||||
#if defined(__VITA__)
|
||||
#define DSU_sendto(sock, buf, len, flags, addr, addrlen) \
|
||||
sceNetSendto((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_recvfrom(sock, buf, len, flags, addr, addrlen) \
|
||||
sceNetRecvfrom((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_GetLastError() sce_net_errno
|
||||
#elif defined(__PSP__)
|
||||
#define DSU_sendto(sock, buf, len, flags, addr, addrlen) \
|
||||
sceNetInetSendto((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_recvfrom(sock, buf, len, flags, addr, addrlen) \
|
||||
sceNetInetRecvfrom((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_GetLastError() sceNetInetGetErrno()
|
||||
#elif defined(__PS2__)
|
||||
/* PS2 uses lwIP */
|
||||
#define DSU_sendto(sock, buf, len, flags, addr, addrlen) \
|
||||
lwip_sendto((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_recvfrom(sock, buf, len, flags, addr, addrlen) \
|
||||
lwip_recvfrom((sock), (buf), (len), (flags), (addr), (addrlen))
|
||||
#define DSU_GetLastError() errno
|
||||
#else
|
||||
/* Standard sendto/recvfrom */
|
||||
#define DSU_sendto sendto
|
||||
#define DSU_recvfrom recvfrom
|
||||
#define DSU_GetLastError() errno
|
||||
#endif
|
||||
|
||||
/* Socket helpers implementation */
|
||||
int DSU_InitSockets(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
return WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
#elif defined(__VITA__)
|
||||
/* PS Vita network initialization is handled by SDL main */
|
||||
return 0;
|
||||
#elif defined(__PSP__)
|
||||
/* PSP network initialization is handled by SDL main */
|
||||
return 0;
|
||||
#elif defined(__PS2__)
|
||||
/* PS2 network initialization is handled by SDL main */
|
||||
return 0;
|
||||
#elif defined(__3DS__)
|
||||
/* 3DS network initialization is handled by SDL main */
|
||||
return 0;
|
||||
#else
|
||||
/* Unix/Linux - no initialization needed */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DSU_QuitSockets(void)
|
||||
void DSU_CleanupSockets(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#elif defined(__VITA__) || defined(__PSP__) || defined(__PS2__) || defined(__3DS__)
|
||||
/* Console platforms handle cleanup elsewhere */
|
||||
#else
|
||||
/* Unix/Linux - no cleanup needed */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +255,17 @@ dsu_socket_t DSU_CreateSocket(Uint16 port)
|
|||
int reuse = 1;
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
#elif defined(__VITA__)
|
||||
/* PS Vita uses different socket creation */
|
||||
int nonblock = 1;
|
||||
#elif defined(__PSP__)
|
||||
/* PSP socket creation */
|
||||
#elif defined(__PS2__)
|
||||
/* PS2 socket creation */
|
||||
int nb = 1;
|
||||
#elif defined(__3DS__)
|
||||
/* 3DS socket creation */
|
||||
int nonblock = 1;
|
||||
#else
|
||||
int flags;
|
||||
#if defined(FIONBIO)
|
||||
|
|
@ -153,17 +273,41 @@ dsu_socket_t DSU_CreateSocket(Uint16 port)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__VITA__)
|
||||
sock = sceNetSocket("DSU_Socket", AF_INET, SOCK_DGRAM, 0);
|
||||
#elif defined(__PSP__)
|
||||
sock = sceNetInetSocket(AF_INET, SOCK_DGRAM, 0);
|
||||
#elif defined(__PS2__)
|
||||
sock = lwip_socket(AF_INET, SOCK_DGRAM, 0);
|
||||
#elif defined(__3DS__)
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#else
|
||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#endif
|
||||
if (sock == DSU_INVALID_SOCKET) {
|
||||
return DSU_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* Allow address reuse */
|
||||
#if !defined(__VITA__) && !defined(__PSP__) && !defined(__PS2__) /* These platforms may not support SO_REUSEADDR */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
|
||||
#endif
|
||||
|
||||
/* Set socket to non-blocking */
|
||||
#ifdef _WIN32
|
||||
ioctlsocket(sock, FIONBIO, &mode);
|
||||
#elif defined(__VITA__)
|
||||
sceNetSetSockOpt(sock, SCE_NET_SOL_SOCKET, SCE_NET_SO_NBIO, &nonblock, sizeof(nonblock));
|
||||
#elif defined(__PSP__)
|
||||
/* PSP: Set non-blocking mode differently */
|
||||
sceNetInetSetNonblock(sock, 1);
|
||||
#elif defined(__PS2__)
|
||||
/* PS2: lwIP non-blocking mode */
|
||||
int nb = 1;
|
||||
lwip_ioctl(sock, FIONBIO, &nb);
|
||||
#elif defined(__3DS__)
|
||||
/* 3DS: Use fcntl for non-blocking */
|
||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
#else
|
||||
#if defined(FIONBIO)
|
||||
if (ioctl(sock, FIONBIO, &nonblock) < 0) {
|
||||
|
|
@ -276,15 +420,15 @@ static int DSU_SendPacket(DSU_Context *ctx, void *packet, size_t size)
|
|||
server.sin_port = DSU_htons(ctx->server_port);
|
||||
server.sin_addr.s_addr = DSU_ipv4_addr(ctx->server_address);
|
||||
|
||||
result = (sendto)(ctx->socket, (const char*)packet, (int)size, 0,
|
||||
(struct sockaddr *)&server, (int)sizeof(server));
|
||||
result = DSU_sendto(ctx->socket, (const char*)packet, (int)size, 0,
|
||||
(struct sockaddr *)&server, (int)sizeof(server));
|
||||
|
||||
if (result < 0) {
|
||||
#ifdef _WIN32
|
||||
int err = WSAGetLastError();
|
||||
SDL_Log("DSU: sendto failed with error %d\n", err);
|
||||
#else
|
||||
SDL_Log("DSU: sendto failed with errno %d\n", errno);
|
||||
SDL_Log("DSU: sendto failed with errno %d\n", DSU_GetLastError());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -505,8 +649,8 @@ int SDLCALL DSU_ReceiverThread(void *data)
|
|||
SDL_Log("DSU: Receiver thread exiting - mutex destroyed\n");
|
||||
break;
|
||||
}
|
||||
received = recvfrom(ctx->socket, (char*)buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&sender, &sender_len);
|
||||
received = DSU_recvfrom(ctx->socket, (char*)buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&sender, &sender_len);
|
||||
|
||||
if (received > (int)sizeof(DSU_Header)) {
|
||||
header = (DSU_Header *)buffer;
|
||||
|
|
@ -581,13 +725,14 @@ int SDLCALL DSU_ReceiverThread(void *data)
|
|||
SDL_Delay(100); /* Back off on errors */
|
||||
}
|
||||
#else
|
||||
if (errno == EBADF) {
|
||||
int err = DSU_GetLastError();
|
||||
if (err == EBADF) {
|
||||
/* Socket closed, exit gracefully */
|
||||
SDL_Log("DSU: Socket closed, receiver thread exiting\n");
|
||||
break;
|
||||
}
|
||||
if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
|
||||
SDL_Log("DSU: recvfrom errno %d\n", errno);
|
||||
if (err != EWOULDBLOCK && err != EAGAIN && err != EINTR) {
|
||||
SDL_Log("DSU: recvfrom errno %d\n", err);
|
||||
SDL_Delay(100);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -656,7 +801,7 @@ static bool DSU_JoystickInit(void)
|
|||
/* Create UDP socket */
|
||||
ctx->socket = DSU_CreateSocket(ctx->client_port);
|
||||
if (ctx->socket == DSU_INVALID_SOCKET) {
|
||||
DSU_QuitSockets();
|
||||
DSU_CleanupSockets();
|
||||
SDL_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -665,7 +810,7 @@ static bool DSU_JoystickInit(void)
|
|||
ctx->slots_mutex = SDL_CreateMutex();
|
||||
if (!ctx->slots_mutex) {
|
||||
DSU_CloseSocket(ctx->socket);
|
||||
DSU_QuitSockets();
|
||||
DSU_CleanupSockets();
|
||||
SDL_free(ctx);
|
||||
SDL_OutOfMemory();
|
||||
return false;
|
||||
|
|
@ -678,7 +823,7 @@ static bool DSU_JoystickInit(void)
|
|||
if (!ctx->receiver_thread) {
|
||||
SDL_DestroyMutex(ctx->slots_mutex);
|
||||
DSU_CloseSocket(ctx->socket);
|
||||
DSU_QuitSockets();
|
||||
DSU_CleanupSockets();
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Failed to create DSU receiver thread");
|
||||
return false;
|
||||
|
|
@ -1049,8 +1194,8 @@ static bool DSU_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumb
|
|||
server.sin_family = AF_INET;
|
||||
server.sin_port = DSU_htons(ctx->server_port);
|
||||
server.sin_addr.s_addr = DSU_ipv4_addr(ctx->server_address);
|
||||
if ((sendto)(ctx->socket, (const char*)&packet, (int)sizeof(packet), 0,
|
||||
(struct sockaddr *)&server, (int)sizeof(server)) < 0) {
|
||||
if (DSU_sendto(ctx->socket, (const char*)&packet, (int)sizeof(packet), 0,
|
||||
(struct sockaddr *)&server, (int)sizeof(server)) < 0) {
|
||||
SDL_SetError("Failed to send rumble packet");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1314,7 +1459,7 @@ static void DSU_JoystickQuit(void)
|
|||
}
|
||||
|
||||
/* Clean up sockets */
|
||||
DSU_QuitSockets();
|
||||
DSU_CleanupSockets();
|
||||
|
||||
/* Clean up mutex */
|
||||
if (ctx->slots_mutex) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue