mirror of
https://github.com/portable-lce/shiggy.git
synced 2026-09-21 23:43:10 +00:00
feat: add shims
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# shiggy
|
||||
|
||||
**sh**immed **iggy**
|
||||
(sh)immed (iggy)
|
||||
|
||||
                                                                                                                                    
|
||||
71
include/iggy_audio_shim.h
Normal file
71
include/iggy_audio_shim.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef IGGY_AUDIO_SHIM_H
|
||||
#define IGGY_AUDIO_SHIM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IGGY_AUDIO_OK 0
|
||||
|
||||
enum IggyAudioOutPort {
|
||||
Main = 0,
|
||||
Bgm = 1,
|
||||
Voice = 2,
|
||||
Personal = 3,
|
||||
PadSpk = 4,
|
||||
Audio3d = 126,
|
||||
Aux = 127,
|
||||
};
|
||||
|
||||
enum IggyAudioOutParamAttr {
|
||||
None = 0,
|
||||
Restricted = 1,
|
||||
MixToMain = 2,
|
||||
};
|
||||
|
||||
enum IggyAudioOutParamFormat {
|
||||
S16Mono = 0,
|
||||
S16Stereo = 1,
|
||||
S16_8CH = 2,
|
||||
FloatMono = 3,
|
||||
FloatStereo = 4,
|
||||
Float_8CH = 5,
|
||||
S16_8CH_Std = 6,
|
||||
Float_8CH_Std = 7
|
||||
};
|
||||
|
||||
typedef union IggyAudioOutParamExtendedInformation {
|
||||
unsigned raw;
|
||||
struct {
|
||||
unsigned data_format : 8; // bits 0.. 7
|
||||
unsigned reserve0 : 8; // bits 8..15
|
||||
unsigned attributes : 4; // bits 16..19
|
||||
unsigned reserve1 : 10; // bits 20..29
|
||||
unsigned : 1; // bit 30 (padding)
|
||||
unsigned unused : 1; // bit 31
|
||||
} bits;
|
||||
} IggyAudioOutParamExtendedInformation;
|
||||
|
||||
|
||||
typedef struct IggyAudioShimCallbacks {
|
||||
int (*iggyAudioOutOpen)(
|
||||
int user_id,
|
||||
enum IggyAudioOutPort port_type,
|
||||
int index,
|
||||
unsigned length,
|
||||
unsigned sample_rate,
|
||||
IggyAudioOutParamExtendedInformation param_type);
|
||||
|
||||
int (*iggyAudioOutSetVolume)(int handle, int flag, int* vol);
|
||||
int (*iggyAudioOutClose)(int handle);
|
||||
int (*iggyAudioOutOutput)(int handle, void* ptr);
|
||||
} IggyAudioShimCallbacks;
|
||||
|
||||
// Registers callback table used by the shim
|
||||
int iggyAudioShimRegisterCallbacks(const IggyAudioShimCallbacks* callbacks);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // IGGY_AUDIO_SHIM_H
|
||||
@@ -114,8 +114,11 @@ patched_relocations = custom_target(
|
||||
],
|
||||
)
|
||||
|
||||
libshiggy = static_library(
|
||||
shiggy = declare_dependency(
|
||||
sources: static_library(
|
||||
'shiggy',
|
||||
meson.project_source_root() / 'src' / 'shims.c',
|
||||
include_directories : include_directories('include'),
|
||||
objects: patched_relocations,
|
||||
)
|
||||
)
|
||||
326
src/shims.c
326
src/shims.c
@@ -0,0 +1,326 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fenv.h>
|
||||
|
||||
#include "iggy_audio_shim.h"
|
||||
|
||||
_Static_assert(sizeof(pthread_t) == 8, "pthread_t must be 8 bytes");
|
||||
_Static_assert(sizeof(int) == 4, "int must be 32 bit");
|
||||
_Static_assert(sizeof(unsigned) == 4, "unsigned must be 32 bit");
|
||||
|
||||
|
||||
// MARK: CRT & Math Shims
|
||||
|
||||
double _Sin(double x) { return sin(x); }
|
||||
double _Log(double x) { return log(x); }
|
||||
|
||||
// Map to the C fenv.h rounding modes
|
||||
int _Fltrounds(void) {
|
||||
switch (fegetround()) {
|
||||
case FE_TOWARDZERO: return 0;
|
||||
case FE_TONEAREST: return 1;
|
||||
case FE_DOWNWARD: return 2;
|
||||
case FE_UPWARD: return 3;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// BSD specific function supposed to return pointer to thread-local errno
|
||||
#if defined(__GLIBC__)
|
||||
int *__error(void) { return __errno_location(); }
|
||||
#else
|
||||
int *__error(void) { return &errno; }
|
||||
#endif
|
||||
|
||||
// Microsoft specific variant of gmtime
|
||||
int gmtime_s(struct tm *tmDest, const time_t *sourceTime) {
|
||||
if (!tmDest || !sourceTime) return EINVAL;
|
||||
if (gmtime_r(sourceTime, tmDest) == NULL) return EINVAL; /* conservative */
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns pointer to ctype classification table
|
||||
const unsigned short *_Getpctype(void) {
|
||||
#if defined(__GLIBC__)
|
||||
return (const unsigned short *)(*__ctype_b_loc());
|
||||
#else
|
||||
// We might still be alright
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: Helpers for heap-allocated opaque objects
|
||||
|
||||
static int alloc_and_init(void **out, size_t size, int (*init_fn)(void *), void (*free_fn)(void *)) {
|
||||
if (!out) return EINVAL;
|
||||
*out = NULL;
|
||||
|
||||
void *p = malloc(size);
|
||||
if (!p) return ENOMEM;
|
||||
|
||||
int rc = init_fn(p);
|
||||
if (rc != 0) {
|
||||
if (free_fn) free_fn(p);
|
||||
else free(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*out = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// MARK: Pthread Shims (opaque handles allocated on heap)
|
||||
|
||||
// Mutex Attributes
|
||||
|
||||
static int mutexattr_init_thunk(void *p) {
|
||||
return pthread_mutexattr_init((pthread_mutexattr_t *)p);
|
||||
}
|
||||
|
||||
int scePthreadMutexattrInit(void **attr) {
|
||||
return alloc_and_init(attr, sizeof(pthread_mutexattr_t), mutexattr_init_thunk, free);
|
||||
}
|
||||
|
||||
int scePthreadMutexattrSettype(void **attr, int type) {
|
||||
if (!attr || !*attr) return EINVAL;
|
||||
return pthread_mutexattr_settype((pthread_mutexattr_t *)*attr, type);
|
||||
}
|
||||
|
||||
int scePthreadMutexattrDestroy(void **attr) {
|
||||
if (!attr || !*attr) return EINVAL;
|
||||
pthread_mutexattr_t *a = (pthread_mutexattr_t *)*attr;
|
||||
|
||||
int rc = pthread_mutexattr_destroy(a);
|
||||
if (rc == 0) {
|
||||
free(a);
|
||||
*attr = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Mutexes
|
||||
|
||||
int scePthreadMutexInit(void **mutex, void **attr, const char *name) {
|
||||
(void)name;
|
||||
|
||||
if (!mutex) return EINVAL;
|
||||
*mutex = NULL;
|
||||
|
||||
pthread_mutex_t *m = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
||||
if (!m) return ENOMEM;
|
||||
|
||||
pthread_mutexattr_t *a = (attr && *attr) ? (pthread_mutexattr_t *)*attr : NULL;
|
||||
|
||||
int rc = pthread_mutex_init(m, a);
|
||||
if (rc != 0) {
|
||||
free(m);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*mutex = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scePthreadMutexLock(void **mutex) {
|
||||
if (!mutex || !*mutex) return EINVAL;
|
||||
return pthread_mutex_lock((pthread_mutex_t *)*mutex);
|
||||
}
|
||||
|
||||
int scePthreadMutexTrylock(void **mutex) {
|
||||
if (!mutex || !*mutex) return EINVAL;
|
||||
return pthread_mutex_trylock((pthread_mutex_t *)*mutex);
|
||||
}
|
||||
|
||||
int scePthreadMutexUnlock(void **mutex) {
|
||||
if (!mutex || !*mutex) return EINVAL;
|
||||
return pthread_mutex_unlock((pthread_mutex_t *)*mutex);
|
||||
}
|
||||
|
||||
int scePthreadMutexTimedlock(void **mutex, unsigned int usecs) {
|
||||
if (!mutex || !*mutex) return EINVAL;
|
||||
|
||||
struct timespec ts;
|
||||
|
||||
// Get current wall clock time
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
|
||||
return errno;
|
||||
|
||||
// Add the relative microseconds to the current time
|
||||
ts.tv_sec += (usecs / 1000000);
|
||||
ts.tv_nsec += (usecs % 1000000) * 1000;
|
||||
|
||||
// Handle nanosecond overflow
|
||||
if (ts.tv_nsec >= 1000000000L) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000L;
|
||||
}
|
||||
|
||||
// Call the standard POSIX function with the absolute time
|
||||
return pthread_mutex_timedlock(*mutex, &ts);
|
||||
}
|
||||
|
||||
int scePthreadMutexDestroy(void **mutex) {
|
||||
if (!mutex || !*mutex) return EINVAL;
|
||||
|
||||
pthread_mutex_t *m = (pthread_mutex_t *)*mutex;
|
||||
int rc = pthread_mutex_destroy(m);
|
||||
if (rc == 0) {
|
||||
free(m);
|
||||
*mutex = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Thread Attributes
|
||||
|
||||
static int attr_init_thunk(void *p) {
|
||||
return pthread_attr_init((pthread_attr_t *)p);
|
||||
}
|
||||
|
||||
int scePthreadAttrInit(void **attr) {
|
||||
return alloc_and_init(attr, sizeof(pthread_attr_t), attr_init_thunk, free);
|
||||
}
|
||||
|
||||
int scePthreadAttrSetstacksize(void **attr, size_t stacksize) {
|
||||
if (!attr || !*attr) return EINVAL;
|
||||
return pthread_attr_setstacksize((pthread_attr_t *)*attr, stacksize);
|
||||
}
|
||||
|
||||
int scePthreadAttrDestroy(void **attr) {
|
||||
if (!attr || !*attr) return EINVAL;
|
||||
|
||||
pthread_attr_t *a = (pthread_attr_t *)*attr;
|
||||
int rc = pthread_attr_destroy(a);
|
||||
if (rc == 0) {
|
||||
free(a);
|
||||
*attr = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Threads
|
||||
|
||||
int scePthreadCreate(pthread_t *thread_out, void **attr, void *(*start_routine)(void *), void *arg, const char *name) {
|
||||
(void)name;
|
||||
|
||||
if (!thread_out || !start_routine) return EINVAL;
|
||||
pthread_attr_t *a = (attr && *attr) ? (pthread_attr_t *)*attr : NULL;
|
||||
return pthread_create(thread_out, a, start_routine, arg);
|
||||
}
|
||||
|
||||
int scePthreadJoin(pthread_t thread, void **value_ptr) {
|
||||
return pthread_join(thread, value_ptr);
|
||||
}
|
||||
|
||||
int scePthreadDetach(pthread_t thread) {
|
||||
return pthread_detach(thread);
|
||||
}
|
||||
|
||||
pthread_t scePthreadSelf(void) {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
void scePthreadYield(void) {
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
int scePthreadSetschedparam(pthread_t thread, int policy, const struct sched_param *param) {
|
||||
if (!param) return EINVAL;
|
||||
return pthread_setschedparam(thread, policy, param);
|
||||
}
|
||||
|
||||
int scePthreadGetschedparam(pthread_t thread, int *policy, struct sched_param *param) {
|
||||
if (!policy || !param) return EINVAL;
|
||||
return pthread_getschedparam(thread, policy, param);
|
||||
}
|
||||
|
||||
// TLS Keys
|
||||
|
||||
int scePthreadKeyCreate(pthread_key_t *key, void (*destructor)(void *), const char *name) {
|
||||
(void)name;
|
||||
if (!key) return EINVAL;
|
||||
return pthread_key_create(key, destructor);
|
||||
}
|
||||
|
||||
int scePthreadSetspecific(pthread_key_t key, const void *value) {
|
||||
return pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
void *scePthreadGetspecific(pthread_key_t key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
// Affinity
|
||||
|
||||
int scePthreadSetaffinity(pthread_t thread, uint64_t cpumask) {
|
||||
(void)thread;
|
||||
(void)cpumask;
|
||||
return 0; // Could return ENOSYS here, but this should be alright too
|
||||
}
|
||||
|
||||
// MARK: Kernel & Hardware Shims
|
||||
|
||||
int sceKernelGettimeofday(struct timeval *tp) {
|
||||
if (!tp) return EINVAL;
|
||||
return gettimeofday(tp, NULL);
|
||||
}
|
||||
|
||||
int sceKernelUsleep(unsigned microseconds) {
|
||||
return usleep(microseconds);
|
||||
}
|
||||
|
||||
// MARK: Audio Shims
|
||||
|
||||
static IggyAudioShimCallbacks g_audioCbs = {};
|
||||
|
||||
int iggyAudioShimRegisterCallbacks(const IggyAudioShimCallbacks* callbacks) {
|
||||
if (callbacks) {
|
||||
g_audioCbs = *callbacks;
|
||||
} else {
|
||||
IggyAudioShimCallbacks cbs = {};
|
||||
g_audioCbs = cbs;
|
||||
}
|
||||
return IGGY_AUDIO_OK;
|
||||
}
|
||||
|
||||
int sceAudioOutOpen(int user_id, enum IggyAudioOutPort port_type, int index, unsigned length, unsigned sample_rate, IggyAudioOutParamExtendedInformation param_type) {
|
||||
if (g_audioCbs.iggyAudioOutOpen)
|
||||
return g_audioCbs.iggyAudioOutOpen(user_id, port_type, index, length, sample_rate, param_type);
|
||||
return IGGY_AUDIO_OK;
|
||||
}
|
||||
|
||||
int sceAudioOutSetVolume(int handle, int flag, int* vol) {
|
||||
if (g_audioCbs.iggyAudioOutSetVolume)
|
||||
return g_audioCbs.iggyAudioOutSetVolume(handle, flag, vol);
|
||||
return IGGY_AUDIO_OK;
|
||||
}
|
||||
|
||||
int sceAudioOutClose(int handle) {
|
||||
if (g_audioCbs.iggyAudioOutClose)
|
||||
return g_audioCbs.iggyAudioOutClose(handle);
|
||||
return IGGY_AUDIO_OK;
|
||||
}
|
||||
|
||||
int sceAudioOutOutput(int handle, void* ptr) {
|
||||
if (g_audioCbs.iggyAudioOutOutput)
|
||||
return g_audioCbs.iggyAudioOutOutput(handle, ptr);
|
||||
return IGGY_AUDIO_OK;
|
||||
}
|
||||
|
||||
// MARK: Misc
|
||||
|
||||
void gdraw_ps4_wait(void) {
|
||||
usleep(1000);
|
||||
}
|
||||
Reference in New Issue
Block a user