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
|
# 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
|
||||||
13
meson.build
13
meson.build
@@ -114,8 +114,11 @@ patched_relocations = custom_target(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
libshiggy = static_library(
|
shiggy = declare_dependency(
|
||||||
'shiggy',
|
sources: static_library(
|
||||||
meson.project_source_root() / 'src' / 'shims.c',
|
'shiggy',
|
||||||
objects: patched_relocations,
|
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