Appl new code style on whole code base

Use a similar code style to bemanitools though reduce indentation
to 2 spaces. Also some other tweaks to be more similar to google
style.
This commit is contained in:
icex2
2021-03-19 15:52:34 +01:00
parent b493b4983a
commit eafb2909d1
322 changed files with 30291 additions and 25084 deletions
+24 -24
View File
@@ -5,49 +5,49 @@
#include "util/log.h"
#include "util/str.h"
typedef int (*system_t)(const char* command);
typedef int (*execv_t)(const char* path, char* const argv[]);
typedef int (*system_t)(const char *command);
typedef int (*execv_t)(const char *path, char *const argv[]);
static bool patch_axmier_block_initialized;
static system_t patch_amixer_block_real_system;
static execv_t patch_amixer_block_real_execv;
// for fst and fex
int system(const char* command)
int system(const char *command)
{
if (!patch_amixer_block_real_system) {
patch_amixer_block_real_system = (system_t) cnh_lib_get_func_addr("system");
}
if (!patch_amixer_block_real_system) {
patch_amixer_block_real_system = (system_t) cnh_lib_get_func_addr("system");
}
if (patch_axmier_block_initialized) {
if (util_str_starts_with(command, "amixer")) {
log_info("Blocking call to amixer: %s", command);
return 0;
}
if (patch_axmier_block_initialized) {
if (util_str_starts_with(command, "amixer")) {
log_info("Blocking call to amixer: %s", command);
return 0;
}
}
return patch_amixer_block_real_system(command);
return patch_amixer_block_real_system(command);
}
// for f2 and prime (yes, they figured using system() isn't a great idea...)
int execv(const char* path, char* const argv[])
int execv(const char *path, char *const argv[])
{
if (!patch_amixer_block_real_execv) {
patch_amixer_block_real_execv = (execv_t) cnh_lib_get_func_addr("execv");
}
if (!patch_amixer_block_real_execv) {
patch_amixer_block_real_execv = (execv_t) cnh_lib_get_func_addr("execv");
}
if (patch_axmier_block_initialized) {
if (util_str_starts_with(path, "/usr/bin/amixer")) {
log_info("Blocking call to amixer: %s", path);
return 0;
}
if (patch_axmier_block_initialized) {
if (util_str_starts_with(path, "/usr/bin/amixer")) {
log_info("Blocking call to amixer: %s", path);
return 0;
}
}
return patch_amixer_block_real_execv(path, argv);
return patch_amixer_block_real_execv(path, argv);
}
void patch_axmier_block_init(void)
{
patch_axmier_block_initialized = true;
log_info("Initialized");
patch_axmier_block_initialized = true;
log_info("Initialized");
}
+129 -107
View File
@@ -9,139 +9,161 @@
#include "util/mem.h"
#include "util/str.h"
typedef int (*getgrnam_r_t)(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result);
typedef int (*getgrnam_r_t)(
const char *name,
struct group *grp,
char *buf,
size_t buflen,
struct group **result);
static getgrnam_r_t patch_asound_fix_real_getgrnam_r;
static char** patch_asound_fix_split_user_list_str(const char* user_list_str)
static char **patch_asound_fix_split_user_list_str(const char *user_list_str)
{
char* user_list_str_cpy = util_str_dup(user_list_str);
char** user_list = util_xmalloc(sizeof(char*));
size_t len_list = 1;
char *user_list_str_cpy = util_str_dup(user_list_str);
char **user_list = util_xmalloc(sizeof(char *));
size_t len_list = 1;
char* ptr = strtok(user_list_str_cpy, ",");
char *ptr = strtok(user_list_str_cpy, ",");
while (ptr != NULL) {
// last token will likely read beyond newline to next : token for next group entry
char* new_line_char = strstr(ptr, "\n");
while (ptr != NULL) {
// last token will likely read beyond newline to next : token for next group
// entry
char *new_line_char = strstr(ptr, "\n");
if (new_line_char) {
*new_line_char = '\0';
}
len_list++;
user_list = util_xrealloc(user_list, len_list * sizeof(char*));
user_list[len_list - 2] = util_str_dup(ptr);
user_list[len_list - 1] = NULL;
ptr = strtok(NULL, ",");
if (new_line_char) {
*new_line_char = '\0';
}
free(user_list_str_cpy);
len_list++;
user_list = util_xrealloc(user_list, len_list * sizeof(char *));
return user_list;
user_list[len_list - 2] = util_str_dup(ptr);
user_list[len_list - 1] = NULL;
ptr = strtok(NULL, ",");
}
free(user_list_str_cpy);
return user_list;
}
static char* patch_asound_fix_user_list_to_str(char** user_list)
static char *patch_asound_fix_user_list_to_str(char **user_list)
{
char** ptr = user_list;
char* str = util_str_dup("\0");
char **ptr = user_list;
char *str = util_str_dup("\0");
while (*ptr != NULL) {
char* mrg = util_str_merge(str, *ptr);
free(str);
str = util_str_merge(mrg, ",");
free(mrg);
while (*ptr != NULL) {
char *mrg = util_str_merge(str, *ptr);
free(str);
str = util_str_merge(mrg, ",");
free(mrg);
ptr++;
}
ptr++;
}
return str;
return str;
}
int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result)
int getgrnam_r(
const char *name,
struct group *grp,
char *buf,
size_t buflen,
struct group **result)
{
if (!patch_asound_fix_real_getgrnam_r) {
patch_asound_fix_real_getgrnam_r = (getgrnam_r_t) cnh_lib_get_func_addr("getgrnam_r");
if (!patch_asound_fix_real_getgrnam_r) {
patch_asound_fix_real_getgrnam_r =
(getgrnam_r_t) cnh_lib_get_func_addr("getgrnam_r");
}
// We expect to use the standard "audio" group here, otherwise detection of
// this is not possible. Intercept and execute the following re-implementation
// of the reading logic from file. I don't know if getgrnam_r usually reads
// from a cached version of /etc/group but I suppose that doesn't matter here.
if (!strcmp(name, "audio")) {
log_debug("Trapping getgrnam_r for audio group of libasound");
FILE *file = fopen("/etc/group", "r");
fseek(file, 0, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
char *buffer = (char *) util_xmalloc(file_size);
if (fread(buffer, file_size, 1, file) != 1) {
log_error("Reading /etc/group file failed: %s", strerror(errno));
free(buffer);
*result = NULL;
return -1;
}
// We expect to use the standard "audio" group here, otherwise detection of this is not possible. Intercept
// and execute the following re-implementation of the reading logic from file. I don't know if getgrnam_r usually
// reads from a cached version of /etc/group but I suppose that doesn't matter here.
if (!strcmp(name, "audio")) {
log_debug("Trapping getgrnam_r for audio group of libasound");
char *str_audio_pos = strstr(buffer, name);
FILE* file = fopen("/etc/group", "r");
fseek(file, 0, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
char* buffer = (char*) util_xmalloc(file_size);
if (fread(buffer, file_size, 1, file) != 1) {
log_error("Reading /etc/group file failed: %s", strerror(errno));
free(buffer);
*result = NULL;
return -1;
}
char* str_audio_pos = strstr(buffer, name);
if (str_audio_pos == NULL) {
log_error("Could not find 'audio' group in /etc/group required by libasound likely for defaults.pcm.ipc_gid"
" from asound.conf. Make sure the group exists.");
free(buffer);
*result = NULL;
return -1;
}
char* tok = strtok(str_audio_pos, ":");
uint8_t cnt = 0;
while (tok != NULL) {
switch (cnt) {
case 0:
grp->gr_name = util_str_dup(tok);
break;
case 1:
grp->gr_passwd = util_str_dup(tok);
break;
case 2:
grp->gr_gid = strtol(tok, NULL, 10);
break;
case 3:
grp->gr_mem = patch_asound_fix_split_user_list_str(tok);
break;
default:
log_error("audio group entry format in /etc/group invalid. Check your /etc/group file!");
free(buffer);
*result = NULL;
return -1;
}
cnt++;
tok = strtok(NULL, ":");
}
char* grp_mem_str = patch_asound_fix_user_list_to_str(grp->gr_mem);
log_debug("Resulting group struct: %s %s %d %s", grp->gr_name, grp->gr_passwd, grp->gr_gid, grp_mem_str);
free(grp_mem_str);
*result = grp;
return 0;
if (str_audio_pos == NULL) {
log_error(
"Could not find 'audio' group in /etc/group required by libasound "
"likely for defaults.pcm.ipc_gid"
" from asound.conf. Make sure the group exists.");
free(buffer);
*result = NULL;
return -1;
}
return patch_asound_fix_real_getgrnam_r(name, grp, buf, buflen, result);
char *tok = strtok(str_audio_pos, ":");
uint8_t cnt = 0;
while (tok != NULL) {
switch (cnt) {
case 0:
grp->gr_name = util_str_dup(tok);
break;
case 1:
grp->gr_passwd = util_str_dup(tok);
break;
case 2:
grp->gr_gid = strtol(tok, NULL, 10);
break;
case 3:
grp->gr_mem = patch_asound_fix_split_user_list_str(tok);
break;
default:
log_error(
"audio group entry format in /etc/group invalid. Check your "
"/etc/group file!");
free(buffer);
*result = NULL;
return -1;
}
cnt++;
tok = strtok(NULL, ":");
}
char *grp_mem_str = patch_asound_fix_user_list_to_str(grp->gr_mem);
log_debug(
"Resulting group struct: %s %s %d %s",
grp->gr_name,
grp->gr_passwd,
grp->gr_gid,
grp_mem_str);
free(grp_mem_str);
*result = grp;
return 0;
}
return patch_asound_fix_real_getgrnam_r(name, grp, buf, buflen, result);
}
void patch_asound_fix_init()
{
log_info("Initialized");
log_info("Initialized");
}
+13 -10
View File
@@ -1,16 +1,19 @@
/**
* Fix a quirk with getgrnam_r in the asound library always failing when loading the asound.conf file and reading the
* /etc/group file. For some reason, it cannot find the audio group entry even if it is available and can be read
* by other applications just fine.
* Fix a quirk with getgrnam_r in the asound library always failing when loading
* the asound.conf file and reading the /etc/group file. For some reason, it
* cannot find the audio group entry even if it is available and can be read by
* other applications just fine.
*
* Your typical asound.conf, which is loaded by libasound in a application that uses it, contains the following line:
* defaults.pcm.ipc_gid audio
* Your typical asound.conf, which is loaded by libasound in a application that
* uses it, contains the following line: defaults.pcm.ipc_gid audio
*
* Finding documentation about what this stuff does it difficult but judging by the name, this seems to be related to
* setting up shared memory IPC for reading and writing data to the sound driver.
* For some reason, this "fails" when the function getgrnam_r is called by libasound. The function itself returns
* successful but with no result. This function reads the entry from /etc/group. libsound queries the "audio" group
* in that case and even if the entry exists, the result is empty for some unknown reason.
* Finding documentation about what this stuff does it difficult but judging by
* the name, this seems to be related to setting up shared memory IPC for
* reading and writing data to the sound driver. For some reason, this "fails"
* when the function getgrnam_r is called by libasound. The function itself
* returns successful but with no result. This function reads the entry from
* /etc/group. libsound queries the "audio" group in that case and even if the
* entry exists, the result is empty for some unknown reason.
*
* This module fixes that issue.
*/
+31 -29
View File
@@ -9,58 +9,60 @@
#include "util/mem.h"
struct patch_blacklist_url_list_elem {
struct util_list_node head;
const char* url;
struct util_list_node head;
const char *url;
};
typedef int (*curl_easy_setopt_t)(int* handle, int option, void* param);
typedef int (*curl_easy_setopt_t)(int *handle, int option, void *param);
static bool patch_blacklist_url_initialized;
static curl_easy_setopt_t patch_blacklist_url_real_curl_easy_setopt;
static struct util_list patch_blacklist_url_list;
int curl_easy_setopt(int* handle, int option, void* param)
int curl_easy_setopt(int *handle, int option, void *param)
{
if (!patch_blacklist_url_real_curl_easy_setopt) {
patch_blacklist_url_real_curl_easy_setopt = (curl_easy_setopt_t) cnh_lib_get_func_addr("curl_easy_setopt");
}
if (!patch_blacklist_url_real_curl_easy_setopt) {
patch_blacklist_url_real_curl_easy_setopt =
(curl_easy_setopt_t) cnh_lib_get_func_addr("curl_easy_setopt");
}
if (patch_blacklist_url_initialized) {
if (patch_blacklist_url_initialized) {
/* option == 10002 to identify that param has a string */
if (option == 10002) {
/* option == 10002 to identify that param has a string */
if (option == 10002) {
struct util_list_node* pos;
struct patch_blacklist_url_list_elem* elem;
struct util_list_node *pos;
struct patch_blacklist_url_list_elem *elem;
for (pos = patch_blacklist_url_list.head; pos != NULL; pos = pos->next) {
elem = containerof(pos, struct patch_blacklist_url_list_elem, head);
for (pos = patch_blacklist_url_list.head; pos != NULL; pos = pos->next) {
elem = containerof(pos, struct patch_blacklist_url_list_elem, head);
if (!memcmp(param, elem->url, strlen(elem->url))) {
log_debug("Blocking url %s", elem->url);
return patch_blacklist_url_real_curl_easy_setopt(handle, option, (void*) "does-not-exist");
}
}
if (!memcmp(param, elem->url, strlen(elem->url))) {
log_debug("Blocking url %s", elem->url);
return patch_blacklist_url_real_curl_easy_setopt(
handle, option, (void *) "does-not-exist");
}
}
}
}
return patch_blacklist_url_real_curl_easy_setopt(handle, option, param);
return patch_blacklist_url_real_curl_easy_setopt(handle, option, param);
}
void patch_blacklist_url_init(void)
{
util_list_init(&patch_blacklist_url_list);
patch_blacklist_url_initialized = true;
log_info("Initialized");
util_list_init(&patch_blacklist_url_list);
patch_blacklist_url_initialized = true;
log_info("Initialized");
}
void patch_blacklist_url_add(const char* url)
void patch_blacklist_url_add(const char *url)
{
struct patch_blacklist_url_list_elem* elem;
struct patch_blacklist_url_list_elem *elem;
elem = util_xmalloc(sizeof(struct patch_blacklist_url_list_elem));
elem->url = strdup(url);
elem = util_xmalloc(sizeof(struct patch_blacklist_url_list_elem));
elem->url = strdup(url);
util_list_append(&patch_blacklist_url_list, &elem->head);
log_info("Add url %s to blacklist", url);
util_list_append(&patch_blacklist_url_list, &elem->head);
log_info("Add url %s to blacklist", url);
}
+1 -1
View File
@@ -14,6 +14,6 @@ void patch_blacklist_url_init(void);
*
* @param url Url to block
*/
void patch_blacklist_url_add(const char* url);
void patch_blacklist_url_add(const char *url);
#endif
+27 -14
View File
@@ -1,36 +1,49 @@
#define LOG_MODULE "block-keyboard-grab"
#include <stdbool.h>
#include <X11/Xutil.h>
#include <stdbool.h>
#include "capnhook/hook/lib.h"
#include "util/log.h"
typedef int (*XGrabKeyboard_t)(Display* display, Window window, Bool owner_events, int pointer_mode, int keyboard_mode,
Time time);
typedef int (*XGrabKeyboard_t)(
Display *display,
Window window,
Bool owner_events,
int pointer_mode,
int keyboard_mode,
Time time);
static XGrabKeyboard_t _patch_main_loop_real_XGrabKeyboard;
static bool _patch_block_keyboard_grab_enable;
int XGrabKeyboard(Display* display, Window window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time)
int XGrabKeyboard(
Display *display,
Window window,
Bool owner_events,
int pointer_mode,
int keyboard_mode,
Time time)
{
if (!_patch_main_loop_real_XGrabKeyboard) {
_patch_main_loop_real_XGrabKeyboard = (XGrabKeyboard_t) cnh_lib_get_func_addr("XGrabKeyboard");
}
if (!_patch_main_loop_real_XGrabKeyboard) {
_patch_main_loop_real_XGrabKeyboard =
(XGrabKeyboard_t) cnh_lib_get_func_addr("XGrabKeyboard");
}
if (_patch_block_keyboard_grab_enable) {
log_debug("Block keyboard grabbing");
return 0;
}
if (_patch_block_keyboard_grab_enable) {
log_debug("Block keyboard grabbing");
return 0;
}
return _patch_main_loop_real_XGrabKeyboard(display, window, owner_events, pointer_mode, keyboard_mode, time);
return _patch_main_loop_real_XGrabKeyboard(
display, window, owner_events, pointer_mode, keyboard_mode, time);
}
void patch_block_keyboard_grab_init()
{
_patch_block_keyboard_grab_enable = true;
_patch_block_keyboard_grab_enable = true;
log_info("Initialized");
log_info("Initialized");
}
+2 -2
View File
@@ -2,8 +2,8 @@
#define PATCH_BLOCK_KEYBOARD_GRAB_H
/**
* Enable blocking of X11 keyboard grabbing which causes Prime to not go to window mode and behave weird on desktop
* machines.
* Enable blocking of X11 keyboard grabbing which causes Prime to not go to
* window mode and behave weird on desktop machines.
*/
void patch_block_keyboard_grab_init();
+113 -67
View File
@@ -1,7 +1,7 @@
#define LOG_MODULE "patch-gfx"
#include <stdbool.h>
#include <X11/Xutil.h>
#include <stdbool.h>
#include "capnhook/hook/lib.h"
@@ -10,11 +10,22 @@
#include "gfx.h"
typedef Window (*XCreateWindow_t)(Display *display, Window parent, int x, int y, unsigned int width,
unsigned int height, unsigned int border_width, int depth, unsigned int _class, Visual *visual,
unsigned long valuemask, XSetWindowAttributes *attributes);
typedef Display* (*XOpenDisplay_t)(const char *display_name);
typedef XVisualInfo* (*glXChooseVisual_t)(Display *dpy, int screen, int *attribList);
typedef Window (*XCreateWindow_t)(
Display *display,
Window parent,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int border_width,
int depth,
unsigned int _class,
Visual *visual,
unsigned long valuemask,
XSetWindowAttributes *attributes);
typedef Display *(*XOpenDisplay_t)(const char *display_name);
typedef XVisualInfo *(*glXChooseVisual_t)(
Display *dpy, int screen, int *attribList);
static bool patch_gfx_force_window = false;
@@ -23,103 +34,138 @@ static XCreateWindow_t patch_gfx_real_XCreateWindow;
static XOpenDisplay_t patch_gfx_real_XOpenDisplay;
static glXChooseVisual_t patch_gfx_real_GlXChooseVisual;
static char* patch_gfx_attrib_list_to_str(int* attrib_list)
static char *patch_gfx_attrib_list_to_str(int *attrib_list)
{
int* ptr = attrib_list;
char* str = util_str_dup("");
char buf[32];
int *ptr = attrib_list;
char *str = util_str_dup("");
char buf[32];
while (*ptr != None) {
sprintf(buf, "%d, ", *ptr);
while (*ptr != None) {
sprintf(buf, "%d, ", *ptr);
char* tmp = util_str_merge(str, buf);
char *tmp = util_str_merge(str, buf);
free(str);
str = tmp;
free(str);
str = tmp;
ptr++;
}
ptr++;
}
return str;
return str;
}
Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height,
unsigned int border_width, int depth, unsigned int _class, Visual *visual, unsigned long valuemask,
XSetWindowAttributes *attributes)
Window XCreateWindow(
Display *display,
Window parent,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int border_width,
int depth,
unsigned int _class,
Visual *visual,
unsigned long valuemask,
XSetWindowAttributes *attributes)
{
log_debug("XCreateWindow");
log_debug("XCreateWindow");
if (!patch_gfx_real_XCreateWindow) {
patch_gfx_real_XCreateWindow = (XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow");
if (!patch_gfx_real_XCreateWindow) {
patch_gfx_real_XCreateWindow =
(XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow");
}
if (patch_gfx_initialized) {
if (valuemask == 0x80A) {
log_info("Patching to enable usage of non nvidia cards.");
/* enables usage of non nvidia cards and newer nvidia models */
valuemask = 0x280A;
}
}
if (patch_gfx_initialized) {
if (patch_gfx_force_window) {
log_info("Forcing window mode");
attributes->override_redirect = 0;
}
if (valuemask == 0x80A) {
log_info("Patching to enable usage of non nvidia cards.");
/* enables usage of non nvidia cards and newer nvidia models */
valuemask = 0x280A;
}
}
if (patch_gfx_force_window) {
log_info("Forcing window mode");
attributes->override_redirect = 0;
}
return patch_gfx_real_XCreateWindow(display, parent, x, y, width, height, border_width, depth, _class, visual,
valuemask, attributes);
return patch_gfx_real_XCreateWindow(
display,
parent,
x,
y,
width,
height,
border_width,
depth,
_class,
visual,
valuemask,
attributes);
}
Display *XOpenDisplay(const char *display_name)
{
if (!patch_gfx_real_XOpenDisplay) {
patch_gfx_real_XOpenDisplay = (XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay");
}
if (!patch_gfx_real_XOpenDisplay) {
patch_gfx_real_XOpenDisplay =
(XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay");
}
log_info("XOpenDisplay: %s", display_name);
log_info("XOpenDisplay: %s", display_name);
Display* res = patch_gfx_real_XOpenDisplay(display_name);
Display *res = patch_gfx_real_XOpenDisplay(display_name);
if (!res) {
log_error("XOpenDisplay returned NULL. This might indicate that your environment is not properly setup. Check "
" that you have GPU drivers installed and configured properly and that OpenGL hardware acceleration is "
" working (use the command line tool \"glxinfo\").");
}
if (!res) {
log_error(
"XOpenDisplay returned NULL. This might indicate that your environment "
"is not properly setup. Check "
" that you have GPU drivers installed and configured properly and that "
"OpenGL hardware acceleration is "
" working (use the command line tool \"glxinfo\").");
}
return res;
return res;
}
XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attribList)
XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attribList)
{
if (!patch_gfx_real_GlXChooseVisual) {
patch_gfx_real_GlXChooseVisual = (glXChooseVisual_t) cnh_lib_get_func_addr("glXChooseVisual");
}
if (!patch_gfx_real_GlXChooseVisual) {
patch_gfx_real_GlXChooseVisual =
(glXChooseVisual_t) cnh_lib_get_func_addr("glXChooseVisual");
}
char* attrib_list_str =patch_gfx_attrib_list_to_str(attribList);
char *attrib_list_str = patch_gfx_attrib_list_to_str(attribList);
log_info("glXChooseVisual: dpy %p, screen %d, attribList %s", dpy, screen, attrib_list_str);
log_info(
"glXChooseVisual: dpy %p, screen %d, attribList %s",
dpy,
screen,
attrib_list_str);
free(attrib_list_str);
free(attrib_list_str);
XVisualInfo* res = patch_gfx_real_GlXChooseVisual(dpy, screen, attribList);
XVisualInfo *res = patch_gfx_real_GlXChooseVisual(dpy, screen, attribList);
if (!res) {
log_error("glXChooseVisual returned NULL. It is likely that your current environment does support hardware"
"acceleration. Either you do not have any GPU drivers installed or the drivers are not configured "
"properly. Fix that and use the command line tool \"glxinfo\" for debugging this.");
}
if (!res) {
log_error(
"glXChooseVisual returned NULL. It is likely that your current "
"environment does support hardware"
"acceleration. Either you do not have any GPU drivers installed or the "
"drivers are not configured "
"properly. Fix that and use the command line tool \"glxinfo\" for "
"debugging this.");
}
return res;
return res;
}
void patch_gfx_init()
{
patch_gfx_initialized = true;
log_info("Initialized");
patch_gfx_initialized = true;
log_info("Initialized");
}
void patch_gfx_force_window_mode()
{
patch_gfx_force_window = true;
patch_gfx_force_window = true;
}
+56 -39
View File
@@ -6,58 +6,75 @@
#include "util/patch.h"
static const uint8_t patch_hasp_login_sig[] = {
0x00, 0xB8, 0x16, 0x00,
0x00, 0x00, 0x8B, 0x4C,
0x24, 0x14, 0x8B, 0x74,
0x24, 0x10, 0x8B, 0x54
};
0x00,
0xB8,
0x16,
0x00,
0x00,
0x00,
0x8B,
0x4C,
0x24,
0x14,
0x8B,
0x74,
0x24,
0x10,
0x8B,
0x54};
static const uint8_t patch_hasp_id_sig[] = {
0x53, 0x83, 0xEC, 0x48,
0xC7, 0x44, 0x24, 0x10
};
0x53, 0x83, 0xEC, 0x48, 0xC7, 0x44, 0x24, 0x10};
void patch_hasp_init(const uint8_t* key_data, size_t len)
void patch_hasp_init(const uint8_t *key_data, size_t len)
{
void* func_api_login;
void* func_api_logout;
void* func_api_decrypt;
void* func_api_getid;
void *func_api_login;
void *func_api_logout;
void *func_api_decrypt;
void *func_api_getid;
func_api_login = util_patch_find_signiture(patch_hasp_login_sig,
sizeof(patch_hasp_login_sig), -16, (void*) 0x80c0000, (void*) 0x80f0000,
16);
func_api_login = util_patch_find_signiture(
patch_hasp_login_sig,
sizeof(patch_hasp_login_sig),
-16,
(void *) 0x80c0000,
(void *) 0x80f0000,
16);
if (!func_api_login) {
log_error("Could not find ApiLogin address");
return;
}
if (!func_api_login) {
log_error("Could not find ApiLogin address");
return;
}
log_debug("ApiLogin at %p", func_api_login);
log_debug("ApiLogin at %p", func_api_login);
func_api_logout = (void*) (((size_t) func_api_login) - 0x130);
log_debug("assuming ApiLogout at %p", func_api_logout);
func_api_logout = (void *) (((size_t) func_api_login) - 0x130);
log_debug("assuming ApiLogout at %p", func_api_logout);
func_api_decrypt = (void*) (((size_t) func_api_login) - 0x200);
log_debug("assuming ApiDecrypt at %p", func_api_decrypt);
func_api_decrypt = (void *) (((size_t) func_api_login) - 0x200);
log_debug("assuming ApiDecrypt at %p", func_api_decrypt);
func_api_getid = util_patch_find_signiture(patch_hasp_id_sig,
sizeof(patch_hasp_id_sig), 0, (void*) 0x8060000, (void*) 0x8090000,
16);
func_api_getid = util_patch_find_signiture(
patch_hasp_id_sig,
sizeof(patch_hasp_id_sig),
0,
(void *) 0x8060000,
(void *) 0x8090000,
16);
if (!func_api_getid) {
log_error("Could not find ApiGetid address");
return;
}
if (!func_api_getid) {
log_error("Could not find ApiGetid address");
return;
}
log_debug("ApiGetid at %p", func_api_getid);
log_debug("ApiGetid at %p", func_api_getid);
util_patch_function((uintptr_t) func_api_login, sec_hasp_api_login);
util_patch_function((uintptr_t) func_api_logout, sec_hasp_api_logout);
util_patch_function((uintptr_t) func_api_decrypt, sec_hasp_api_decrypt);
util_patch_function((uintptr_t) func_api_getid, sec_hasp_api_getid);
util_patch_function((uintptr_t) func_api_login, sec_hasp_api_login);
util_patch_function((uintptr_t) func_api_logout, sec_hasp_api_logout);
util_patch_function((uintptr_t) func_api_decrypt, sec_hasp_api_decrypt);
util_patch_function((uintptr_t) func_api_getid, sec_hasp_api_getid);
sec_hasp_init(key_data, len);
sec_hasp_init(key_data, len);
log_info("Initialized");
log_info("Initialized");
}
+1 -1
View File
@@ -10,6 +10,6 @@
* @param key_data Pointer to loaded key data (key table)
* @param len Length of the buffer
*/
void patch_hasp_init(const uint8_t* key_data, size_t len);
void patch_hasp_init(const uint8_t *key_data, size_t len);
#endif
+13 -14
View File
@@ -8,33 +8,32 @@
static pthread_t patch_hasp_thread;
static void* patch_hasp_thread_run(void* args)
static void *patch_hasp_thread_run(void *args)
{
log_info("Running hasp server thread");
log_info("Running hasp server thread");
sec_hasp_server_run();
sec_hasp_server_run();
log_info("Finished hasp server thread");
log_info("Finished hasp server thread");
return NULL;
return NULL;
}
void patch_hasp_init(const uint8_t* key_data, size_t len)
void patch_hasp_init(const uint8_t *key_data, size_t len)
{
sec_hasp_server_init(key_data, len);
sec_hasp_server_init(key_data, len);
/* Run the daemon in another thread */
pthread_create(&patch_hasp_thread, NULL,
patch_hasp_thread_run, NULL);
/* Run the daemon in another thread */
pthread_create(&patch_hasp_thread, NULL, patch_hasp_thread_run, NULL);
log_info("Initialized");
log_info("Initialized");
}
void patch_hasp_shutdown(void)
{
log_info("Shutting down");
log_info("Shutting down");
sec_hasp_server_shutdown();
sec_hasp_server_shutdown();
pthread_join(patch_hasp_thread_run, NULL);
pthread_join(patch_hasp_thread_run, NULL);
}
+3 -2
View File
@@ -1,5 +1,6 @@
/**
* Patch module to install the dongle emulator for a hasp dongle (runs a local server)
* Patch module to install the dongle emulator for a hasp dongle (runs a local
* server)
*/
#ifndef PATCH_HASP2_H
#define PATCH_HASP2_H
@@ -12,7 +13,7 @@
* @param key_data Pointer to loaded key data (attributes and key table)
* @param len Length of the buffer
*/
void patch_hasp_init(const uint8_t* key_data, size_t len);
void patch_hasp_init(const uint8_t *key_data, size_t len);
/**
* Shutdown and remove the emulator
+193 -185
View File
@@ -10,248 +10,256 @@
#include "util/log.h"
static const uint8_t* patch_hdd_check_boot_area;
static const uint8_t *patch_hdd_check_boot_area;
static int patch_hdd_check_fd = -1;
static FILE* patch_hdd_check_file = NULL;
static FILE *patch_hdd_check_file = NULL;
static size_t patch_hdd_check_boot_area_size;
static size_t patch_hdd_check_boot_area_fp;
static enum cnh_result patch_hdd_check_filehook(struct cnh_filehook_irp *irp)
{
enum cnh_result result;
enum cnh_result result;
result = CNH_RESULT_SUCCESS;
result = CNH_RESULT_SUCCESS;
assert(irp);
assert(irp);
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && (!patch_hdd_check_file || irp->file != patch_hdd_check_file)) {
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN &&
(!patch_hdd_check_file || irp->file != patch_hdd_check_file)) {
return cnh_filehook_invoke_next(irp);
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN: {
if (!strcmp(irp->open_filename, "/dev/hdd")) {
patch_hdd_check_file = cnh_filehook_open_dummy_file_handle();
irp->file = patch_hdd_check_file;
log_debug("/dev/hdd fopened: %p", patch_hdd_check_file);
} else {
return cnh_filehook_invoke_next(irp);
}
break;
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN:
{
if (!strcmp(irp->open_filename, "/dev/hdd")) {
patch_hdd_check_file = cnh_filehook_open_dummy_file_handle();
irp->file = patch_hdd_check_file;
case CNH_FILEHOOK_IRP_OP_READ: {
uint32_t len;
log_debug("/dev/hdd fopened: %p", patch_hdd_check_file);
} else {
return cnh_filehook_invoke_next(irp);
}
log_debug(
"fread, pos 0x%X, bytes %d",
patch_hdd_check_boot_area_fp,
irp->read.nbytes);
break;
}
/* read up to eof, only */
if (patch_hdd_check_boot_area_fp + irp->read.nbytes <
patch_hdd_check_boot_area_size) {
len = irp->read.nbytes;
} else {
len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp;
}
case CNH_FILEHOOK_IRP_OP_READ:
{
uint32_t len;
memcpy(
irp->read.bytes,
patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp,
len);
log_debug("fread, pos 0x%X, bytes %d", patch_hdd_check_boot_area_fp, irp->read.nbytes);
patch_hdd_check_boot_area_fp += len;
irp->read.pos = len;
/* read up to eof, only */
if (patch_hdd_check_boot_area_fp + irp->read.nbytes < patch_hdd_check_boot_area_size) {
len = irp->read.nbytes;
} else {
len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp;
}
break;
}
memcpy(irp->read.bytes, patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp, len);
case CNH_FILEHOOK_IRP_OP_WRITE: {
// Apparently, Prime starts writing to /dev/hdd, stub
log_debug("fwrite");
patch_hdd_check_boot_area_fp += len;
irp->read.pos = len;
break;
}
break;
}
case CNH_FILEHOOK_IRP_OP_SEEK: {
/* TODO this is not verified to work, yet
not needed on older games as it seems (zero for example)
patch seeking for CRED file so we can avoid a huge hdd file */
if (irp->seek_offset == 0x1F70000) {
log_debug("fseek: fake for hdd (0x1F70000)");
irp->seek_offset = 1024;
irp->seek_origin = SEEK_SET;
} else if (irp->seek_offset == 0x1F70800) {
log_debug("fseek: fake for hdd (0x1F70800)");
irp->seek_offset = 1024 + 2048;
irp->seek_origin = SEEK_SET;
}
case CNH_FILEHOOK_IRP_OP_WRITE:
{
// Apparently, Prime starts writing to /dev/hdd, stub
log_debug("fwrite");
switch (irp->seek_origin) {
case SEEK_SET:
patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset;
break;
break;
}
case SEEK_CUR:
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
case CNH_FILEHOOK_IRP_OP_SEEK:
{
/* TODO this is not verified to work, yet
not needed on older games as it seems (zero for example)
patch seeking for CRED file so we can avoid a huge hdd file */
if (irp->seek_offset == 0x1F70000) {
log_debug("fseek: fake for hdd (0x1F70000)");
irp->seek_offset = 1024;
irp->seek_origin = SEEK_SET;
} else if (irp->seek_offset == 0x1F70800) {
log_debug("fseek: fake for hdd (0x1F70800)");
irp->seek_offset = 1024 + 2048;
irp->seek_origin = SEEK_SET;
}
switch (irp->seek_origin) {
case SEEK_SET:
patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset;
break;
case SEEK_CUR:
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
case SEEK_END:
patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size;
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
default:
log_die("Unhandled origin %d", irp->seek_origin);
break;
}
log_debug("fseek, offset 0x%X, origin %d", irp->seek_offset, irp->seek_origin);
break;
}
case CNH_FILEHOOK_IRP_OP_CLOSE:
patch_hdd_check_file = NULL;
log_debug("/dev/hdd fclosed");
/* Actually close dummy handle */
return cnh_filehook_invoke_next(irp);
case SEEK_END:
patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size;
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
default:
log_warn("Unhandled file op: %d", irp->op);
break;
log_die("Unhandled origin %d", irp->seek_origin);
break;
}
log_debug(
"fseek, offset 0x%X, origin %d", irp->seek_offset, irp->seek_origin);
break;
}
return result;
case CNH_FILEHOOK_IRP_OP_CLOSE:
patch_hdd_check_file = NULL;
log_debug("/dev/hdd fclosed");
/* Actually close dummy handle */
return cnh_filehook_invoke_next(irp);
default:
log_warn("Unhandled file op: %d", irp->op);
break;
}
return result;
}
static enum cnh_result patch_hdd_check_iohook(struct cnh_iohook_irp *irp)
{
enum cnh_result result;
enum cnh_result result;
result = CNH_RESULT_SUCCESS;
result = CNH_RESULT_SUCCESS;
assert(irp);
assert(irp);
if ((irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != patch_hdd_check_fd) &&
(irp->op != CNH_IOHOOK_IRP_OP_FDOPEN || irp->fdopen_fd != patch_hdd_check_fd)) {
if ((irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != patch_hdd_check_fd) &&
(irp->op != CNH_IOHOOK_IRP_OP_FDOPEN ||
irp->fdopen_fd != patch_hdd_check_fd)) {
return cnh_iohook_invoke_next(irp);
}
switch (irp->op) {
case CNH_IOHOOK_IRP_OP_OPEN: {
if (!strcmp(irp->open_filename, "/dev/hdd")) {
patch_hdd_check_fd = cnh_iohook_open_dummy_fd();
irp->fd = patch_hdd_check_fd;
log_debug("/dev/hdd opened: %d", patch_hdd_check_fd);
} else {
return cnh_iohook_invoke_next(irp);
}
break;
}
switch (irp->op) {
case CNH_IOHOOK_IRP_OP_OPEN:
{
if (!strcmp(irp->open_filename, "/dev/hdd")) {
patch_hdd_check_fd = cnh_iohook_open_dummy_fd();
irp->fd = patch_hdd_check_fd;
case CNH_IOHOOK_IRP_OP_FDOPEN: {
patch_hdd_check_file = cnh_filehook_open_dummy_file_handle();
irp->fdopen_res = patch_hdd_check_file;
log_debug("/dev/hdd opened: %d", patch_hdd_check_fd);
} else {
return cnh_iohook_invoke_next(irp);
}
log_debug("/dev/hdd fdopen: %p", patch_hdd_check_file);
break;
}
break;
}
case CNH_IOHOOK_IRP_OP_FDOPEN:
{
patch_hdd_check_file = cnh_filehook_open_dummy_file_handle();
irp->fdopen_res = patch_hdd_check_file;
case CNH_IOHOOK_IRP_OP_READ: {
uint32_t len;
log_debug("/dev/hdd fdopen: %p", patch_hdd_check_file);
log_debug(
"read, pos 0x%X, bytes %d",
patch_hdd_check_boot_area_fp,
irp->read.nbytes);
break;
}
/* read up to eof, only */
if (patch_hdd_check_boot_area_fp + irp->read.nbytes <
patch_hdd_check_boot_area_size) {
len = irp->read.nbytes;
} else {
len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp;
}
case CNH_IOHOOK_IRP_OP_READ:
{
uint32_t len;
memcpy(
irp->read.bytes,
patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp,
len);
log_debug("read, pos 0x%X, bytes %d", patch_hdd_check_boot_area_fp, irp->read.nbytes);
patch_hdd_check_boot_area_fp += len;
irp->read.pos = len;
/* read up to eof, only */
if (patch_hdd_check_boot_area_fp + irp->read.nbytes < patch_hdd_check_boot_area_size) {
len = irp->read.nbytes;
} else {
len = patch_hdd_check_boot_area_size - patch_hdd_check_boot_area_fp;
}
break;
}
memcpy(irp->read.bytes, patch_hdd_check_boot_area + patch_hdd_check_boot_area_fp, len);
case CNH_IOHOOK_IRP_OP_SEEK: {
log_debug("Seek: offset %d, orig %d", irp->seek_offset, irp->seek_origin);
patch_hdd_check_boot_area_fp += len;
irp->read.pos = len;
switch (irp->seek_origin) {
case SEEK_SET:
patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset;
break;
break;
}
case SEEK_CUR:
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
case CNH_IOHOOK_IRP_OP_SEEK:
{
log_debug("Seek: offset %d, orig %d", irp->seek_offset, irp->seek_origin);
switch (irp->seek_origin) {
case SEEK_SET:
patch_hdd_check_boot_area_fp = (size_t) irp->seek_offset;
break;
case SEEK_CUR:
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
case SEEK_END:
patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size;
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
default:
log_die("Unhandled origin %d", irp->seek_origin);
break;
}
irp->seek_pos = patch_hdd_check_boot_area_fp;
break;
}
case CNH_IOHOOK_IRP_OP_IOCTL:
{
/* hdd information request */
if (irp->ioctl_req == HDIO_GET_IDENTITY) {
log_info("ioctl: fake ioctl for hdd (0x30D)");
/* just return empty data instead of real data */
struct hd_driveid* drid = (struct hd_driveid*) irp->ioctl.bytes;
memset(drid, 0, sizeof(struct hd_driveid));
irp->ioctl.pos = 0;
}
break;
}
case CNH_IOHOOK_IRP_OP_CLOSE:
patch_hdd_check_fd = -1;
log_debug("/dev/hdd closed");
/* Actually close dummy handle */
return cnh_iohook_invoke_next(irp);
case SEEK_END:
patch_hdd_check_boot_area_fp = patch_hdd_check_boot_area_size;
patch_hdd_check_boot_area_fp += irp->seek_offset;
break;
default:
log_warn("Unhandled io op: %d", irp->op);
break;
log_die("Unhandled origin %d", irp->seek_origin);
break;
}
irp->seek_pos = patch_hdd_check_boot_area_fp;
break;
}
return result;
case CNH_IOHOOK_IRP_OP_IOCTL: {
/* hdd information request */
if (irp->ioctl_req == HDIO_GET_IDENTITY) {
log_info("ioctl: fake ioctl for hdd (0x30D)");
/* just return empty data instead of real data */
struct hd_driveid *drid = (struct hd_driveid *) irp->ioctl.bytes;
memset(drid, 0, sizeof(struct hd_driveid));
irp->ioctl.pos = 0;
}
break;
}
case CNH_IOHOOK_IRP_OP_CLOSE:
patch_hdd_check_fd = -1;
log_debug("/dev/hdd closed");
/* Actually close dummy handle */
return cnh_iohook_invoke_next(irp);
default:
log_warn("Unhandled io op: %d", irp->op);
break;
}
return result;
}
void patch_hdd_check_init(const uint8_t* boot_area_buffer, size_t len)
void patch_hdd_check_init(const uint8_t *boot_area_buffer, size_t len)
{
patch_hdd_check_boot_area = boot_area_buffer;
patch_hdd_check_boot_area_size = len;
patch_hdd_check_boot_area = boot_area_buffer;
patch_hdd_check_boot_area_size = len;
cnh_iohook_push_handler(patch_hdd_check_iohook);
cnh_filehook_push_handler(patch_hdd_check_filehook);
cnh_iohook_push_handler(patch_hdd_check_iohook);
cnh_filehook_push_handler(patch_hdd_check_filehook);
log_info("Initialized: boot area size %d", patch_hdd_check_boot_area_size);
log_info("Initialized: boot area size %d", patch_hdd_check_boot_area_size);
}
+1 -1
View File
@@ -11,6 +11,6 @@
* @param boot_area_buffer Buffer with boot area sections of a real drive
* @param len Length of buffer provided
*/
void patch_hdd_check_init(const uint8_t* boot_area_buffer, size_t len);
void patch_hdd_check_init(const uint8_t *boot_area_buffer, size_t len);
#endif
+24 -19
View File
@@ -8,29 +8,34 @@
#include "util/log.h"
void patch_hook_mon_init(bool monitor_io, bool monitor_file, bool monitor_fs, bool monitor_usb, bool monitor_open)
void patch_hook_mon_init(
bool monitor_io,
bool monitor_file,
bool monitor_fs,
bool monitor_usb,
bool monitor_open)
{
if (monitor_open) {
cnh_iohook_push_handler(cnh_fileopen_mon_iohook);
cnh_filehook_push_handler(cnh_fileopen_mon_filehook);
cnh_fshook_push_handler(cnh_fileopen_mon_fshook);
}
if (monitor_open) {
cnh_iohook_push_handler(cnh_fileopen_mon_iohook);
cnh_filehook_push_handler(cnh_fileopen_mon_filehook);
cnh_fshook_push_handler(cnh_fileopen_mon_fshook);
}
if (monitor_io) {
cnh_iohook_push_handler(cnh_iohook_mon);
}
if (monitor_io) {
cnh_iohook_push_handler(cnh_iohook_mon);
}
if (monitor_file) {
cnh_filehook_push_handler(cnh_filehook_mon);
}
if (monitor_file) {
cnh_filehook_push_handler(cnh_filehook_mon);
}
if (monitor_fs) {
cnh_fshook_push_handler(cnh_fshook_mon);
}
if (monitor_fs) {
cnh_fshook_push_handler(cnh_fshook_mon);
}
if (monitor_usb) {
cnh_usbhook_push_handler(cnh_usbhook_mon);
}
if (monitor_usb) {
cnh_usbhook_push_handler(cnh_usbhook_mon);
}
log_info("Initialized");
log_info("Initialized");
}
+8 -2
View File
@@ -1,5 +1,6 @@
/**
* Patch module for monitoring various system calls. For development and debugging purpose.
* Patch module for monitoring various system calls. For development and
* debugging purpose.
*/
#ifndef PATCH_HOOK_MON_H
#define PATCH_HOOK_MON_H
@@ -15,6 +16,11 @@
* @param monitor_usb True to enable monitoring of usb calls
* @param monitor_open True to enable monitoring of any file/device open calls
*/
void patch_hook_mon_init(bool monitor_io, bool monitor_file, bool monitor_fs, bool monitor_usb, bool monitor_open);
void patch_hook_mon_init(
bool monitor_io,
bool monitor_file,
bool monitor_fs,
bool monitor_usb,
bool monitor_open);
#endif
+177 -155
View File
@@ -1,8 +1,8 @@
#define LOG_MODULE "patch-main-loop"
#include <X11/Xutil.h>
#include <pthread.h>
#include <stdbool.h>
#include <X11/Xutil.h>
#include "ptapi/io/x11-input-hook.h"
@@ -13,223 +13,245 @@
#include "util/log.h"
typedef int (*XPending_t)(Display* display);
typedef int (*XNextEvent_t)(Display* display, XEvent* event_return);
typedef int (*XPending_t)(Display *display);
typedef int (*XNextEvent_t)(Display *display, XEvent *event_return);
typedef const struct ptapi_io_x11_input_hook_handler* (*ptapi_io_x11_input_handler_hook_t)(void);
typedef const struct ptapi_io_x11_input_hook_handler *(
*ptapi_io_x11_input_handler_hook_t)(void);
static XPending_t _patch_main_loop_real_XPending;
static XNextEvent_t _patch_main_loop_real_XNextEvent;
static void _patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler);
static bool _patch_main_loop_is_key_repeated(Display* display, XEvent* event);
static void
_patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler);
static bool _patch_main_loop_is_key_repeated(Display *display, XEvent *event);
static __sighandler_t _patch_main_loop_sigalarm_orig_handler;
static bool _patch_main_loop_disable_built_in_inputs;
static bool _patch_main_loop_disable_mk3_linux_ports_built_in_inputs;
static pthread_mutex_t _patch_main_loop_input_handlers_lock;
static const struct ptapi_io_x11_input_hook_handler** _patch_main_loop_input_handlers;
static const struct ptapi_io_x11_input_hook_handler *
*_patch_main_loop_input_handlers;
static size_t _patch_main_loop_num_input_handlers;
void patch_main_loop_init(bool fix_sigalarm_main_loop, bool disable_built_in_inputs, bool disable_mk3_linux_port_inputs)
void patch_main_loop_init(
bool fix_sigalarm_main_loop,
bool disable_built_in_inputs,
bool disable_mk3_linux_port_inputs)
{
_patch_main_loop_disable_built_in_inputs = disable_built_in_inputs;
_patch_main_loop_disable_mk3_linux_ports_built_in_inputs = disable_mk3_linux_port_inputs;
_patch_main_loop_disable_built_in_inputs = disable_built_in_inputs;
_patch_main_loop_disable_mk3_linux_ports_built_in_inputs =
disable_mk3_linux_port_inputs;
_patch_main_loop_sigalarm_orig_handler = NULL;
_patch_main_loop_sigalarm_orig_handler = NULL;
if (fix_sigalarm_main_loop) {
log_info("Applying sigalarm handler fix");
cnh_sig_install(SIGALRM, _patch_main_loop_sigalarm_handler);
}
if (fix_sigalarm_main_loop) {
log_info("Applying sigalarm handler fix");
cnh_sig_install(SIGALRM, _patch_main_loop_sigalarm_handler);
}
pthread_mutex_init(&_patch_main_loop_input_handlers_lock, NULL);
pthread_mutex_init(&_patch_main_loop_input_handlers_lock, NULL);
log_info("Initialized, disable built-in inputs %d", disable_built_in_inputs);
log_info("Initialized, disable built-in inputs %d", disable_built_in_inputs);
}
void patch_main_loop_add_x11_input_handler(const char* lib_with_handler_impl)
void patch_main_loop_add_x11_input_handler(const char *lib_with_handler_impl)
{
const struct ptapi_io_x11_input_hook_handler** new_array;
size_t new_size;
void* lib_handle;
ptapi_io_x11_input_handler_hook_t input_handler_hook_func;
const struct ptapi_io_x11_input_hook_handler* input_handler_hook;
const struct ptapi_io_x11_input_hook_handler **new_array;
size_t new_size;
void *lib_handle;
ptapi_io_x11_input_handler_hook_t input_handler_hook_func;
const struct ptapi_io_x11_input_hook_handler *input_handler_hook;
if (!lib_with_handler_impl) {
log_die("No library path with input handler implementation specified");
}
if (!lib_with_handler_impl) {
log_die("No library path with input handler implementation specified");
}
log_info("Loading library with x11-input-handler api implementation %s", lib_with_handler_impl);
log_info(
"Loading library with x11-input-handler api implementation %s",
lib_with_handler_impl);
lib_handle = cnh_lib_load(lib_with_handler_impl);
lib_handle = cnh_lib_load(lib_with_handler_impl);
input_handler_hook_func = (ptapi_io_x11_input_handler_hook_t)
cnh_lib_get_func_addr_handle(lib_handle, "ptapi_io_x11_input_handler_hook");
input_handler_hook_func =
(ptapi_io_x11_input_handler_hook_t) cnh_lib_get_func_addr_handle(
lib_handle, "ptapi_io_x11_input_handler_hook");
input_handler_hook = input_handler_hook_func();
input_handler_hook = input_handler_hook_func();
if (!input_handler_hook) {
log_warn("Library impl %s returned NULL hook handler, skipping", lib_with_handler_impl);
return;
}
if (!input_handler_hook) {
log_warn(
"Library impl %s returned NULL hook handler, skipping",
lib_with_handler_impl);
return;
}
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
new_size = _patch_main_loop_num_input_handlers + 1;
new_array = realloc(_patch_main_loop_input_handlers, new_size * sizeof(struct ptapi_io_input_hook_handler*));
new_size = _patch_main_loop_num_input_handlers + 1;
new_array = realloc(
_patch_main_loop_input_handlers,
new_size * sizeof(struct ptapi_io_input_hook_handler *));
if (new_array != NULL) {
_patch_main_loop_input_handlers = new_array;
if (new_array != NULL) {
_patch_main_loop_input_handlers = new_array;
_patch_main_loop_input_handlers[_patch_main_loop_num_input_handlers++] = input_handler_hook;
} else {
log_die("Out of memory");
}
_patch_main_loop_input_handlers[_patch_main_loop_num_input_handlers++] =
input_handler_hook;
} else {
log_die("Out of memory");
}
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
log_debug("Added input handler %p of lib %s", input_handler_hook, lib_with_handler_impl);
log_debug(
"Added input handler %p of lib %s",
input_handler_hook,
lib_with_handler_impl);
}
int XPending(Display* display)
int XPending(Display *display)
{
if (!_patch_main_loop_real_XPending) {
_patch_main_loop_real_XPending = (XPending_t) cnh_lib_get_func_addr("XPending");
}
if (!_patch_main_loop_real_XPending) {
_patch_main_loop_real_XPending =
(XPending_t) cnh_lib_get_func_addr("XPending");
}
/* poll the original SIGALRM handler to drive the pump engine */
if (_patch_main_loop_sigalarm_orig_handler) {
_patch_main_loop_sigalarm_orig_handler(SIGALRM);
}
/* poll the original SIGALRM handler to drive the pump engine */
if (_patch_main_loop_sigalarm_orig_handler) {
_patch_main_loop_sigalarm_orig_handler(SIGALRM);
}
return _patch_main_loop_real_XPending(display);
return _patch_main_loop_real_XPending(display);
}
int XNextEvent(Display* display, XEvent* event_return)
int XNextEvent(Display *display, XEvent *event_return)
{
int res;
KeySym key;
int res;
KeySym key;
if (!_patch_main_loop_real_XNextEvent) {
_patch_main_loop_real_XNextEvent = (XNextEvent_t) cnh_lib_get_func_addr("XNextEvent");
}
if (!_patch_main_loop_real_XNextEvent) {
_patch_main_loop_real_XNextEvent =
(XNextEvent_t) cnh_lib_get_func_addr("XNextEvent");
}
/* Trap KeyPress and KeyRelease events */
res = _patch_main_loop_real_XNextEvent(display, event_return);
/* Trap KeyPress and KeyRelease events */
res = _patch_main_loop_real_XNextEvent(display, event_return);
switch (event_return->type) {
case KeyPress:
{
/* Mask out the modifier states X11 sets and read again */
event_return->xkey.state &= ~ShiftMask;
event_return->xkey.state &= ~LockMask;
switch (event_return->type) {
case KeyPress: {
/* Mask out the modifier states X11 sets and read again */
event_return->xkey.state &= ~ShiftMask;
event_return->xkey.state &= ~LockMask;
XLookupString(&event_return->xkey, 0, 0, &key, 0);
XLookupString(&event_return->xkey, 0, 0, &key, 0);
/* Swallow some keys to disable them */
if (_patch_main_loop_disable_built_in_inputs) {
if (key == XK_F1 || key == XK_F2 || key == XK_F3) {
event_return->type = GenericEvent;
}
}
/* Swallow some keys to disable them */
if (_patch_main_loop_disable_built_in_inputs) {
if (key == XK_F1 || key == XK_F2 || key == XK_F3) {
event_return->type = GenericEvent;
}
}
/* Swallow all built-in inputs of the MK3 ports */
if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) {
if (key == XK_g || key == XK_h || key == XK_j || key == XK_k || key == XK_l ||
key == XK_q || key == XK_e || key == XK_s || key == XK_z || key == XK_c ||
key == XK_KP_7 || key == XK_KP_9 || key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) {
event_return->type = GenericEvent;
}
}
/* Swallow all built-in inputs of the MK3 ports */
if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) {
if (key == XK_g || key == XK_h || key == XK_j || key == XK_k ||
key == XK_l || key == XK_q || key == XK_e || key == XK_s ||
key == XK_z || key == XK_c || key == XK_KP_7 || key == XK_KP_9 ||
key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) {
event_return->type = GenericEvent;
}
}
/* Dispatch to external input handlers */
if (_patch_main_loop_num_input_handlers > 0) {
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
/* Dispatch to external input handlers */
if (_patch_main_loop_num_input_handlers > 0) {
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) {
if (_patch_main_loop_input_handlers[i]->dispatch_key_press) {
_patch_main_loop_input_handlers[i]->dispatch_key_press(key);
}
}
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
}
break;
for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) {
if (_patch_main_loop_input_handlers[i]->dispatch_key_press) {
_patch_main_loop_input_handlers[i]->dispatch_key_press(key);
}
}
case KeyRelease:
{
/* Mask out the modifier states X11 sets and read again */
event_return->xkey.state &= ~ShiftMask;
event_return->xkey.state &= ~LockMask;
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
}
XLookupString(&event_return->xkey, 0, 0, &key, 0);
break;
}
/* Swallow some keys to disable them */
if (_patch_main_loop_disable_built_in_inputs) {
if (key == XK_F1 || key == XK_F2 || key == XK_F3) {
event_return->type = GenericEvent;
}
}
case KeyRelease: {
/* Mask out the modifier states X11 sets and read again */
event_return->xkey.state &= ~ShiftMask;
event_return->xkey.state &= ~LockMask;
/* Swallow all built-in inputs of the MK3 ports */
if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) {
if (key == XK_g || key == XK_h || key == XK_j || key == XK_k || key == XK_l ||
key == XK_q || key == XK_e || key == XK_s || key == XK_z || key == XK_c ||
key == XK_KP_7 || key == XK_KP_9 || key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) {
event_return->type = GenericEvent;
}
}
XLookupString(&event_return->xkey, 0, 0, &key, 0);
/* Dispatch to external input handlers */
if (_patch_main_loop_num_input_handlers > 0) {
/* Dispatch release if key is not repeated */
if (!_patch_main_loop_is_key_repeated(display, event_return)) {
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) {
if (_patch_main_loop_input_handlers[i]->dispatch_key_release) {
_patch_main_loop_input_handlers[i]->dispatch_key_release(key);
}
}
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
}
}
break;
/* Swallow some keys to disable them */
if (_patch_main_loop_disable_built_in_inputs) {
if (key == XK_F1 || key == XK_F2 || key == XK_F3) {
event_return->type = GenericEvent;
}
}
default:
break;
/* Swallow all built-in inputs of the MK3 ports */
if (_patch_main_loop_disable_mk3_linux_ports_built_in_inputs) {
if (key == XK_g || key == XK_h || key == XK_j || key == XK_k ||
key == XK_l || key == XK_q || key == XK_e || key == XK_s ||
key == XK_z || key == XK_c || key == XK_KP_7 || key == XK_KP_9 ||
key == XK_KP_5 || key == XK_KP_1 || key == XK_KP_3) {
event_return->type = GenericEvent;
}
}
/* Dispatch to external input handlers */
if (_patch_main_loop_num_input_handlers > 0) {
/* Dispatch release if key is not repeated */
if (!_patch_main_loop_is_key_repeated(display, event_return)) {
pthread_mutex_lock(&_patch_main_loop_input_handlers_lock);
for (size_t i = 0; i < _patch_main_loop_num_input_handlers; i++) {
if (_patch_main_loop_input_handlers[i]->dispatch_key_release) {
_patch_main_loop_input_handlers[i]->dispatch_key_release(key);
}
}
pthread_mutex_unlock(&_patch_main_loop_input_handlers_lock);
}
}
break;
}
return res;
default:
break;
}
return res;
}
static void _patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler)
static void
_patch_main_loop_sigalarm_handler(int signal, __sighandler_t orig_handler)
{
/* do nothing on sigalrm */
_patch_main_loop_sigalarm_orig_handler = orig_handler;
/* do nothing on sigalrm */
_patch_main_loop_sigalarm_orig_handler = orig_handler;
}
static bool _patch_main_loop_is_key_repeated(Display* display, XEvent* event)
static bool _patch_main_loop_is_key_repeated(Display *display, XEvent *event)
{
/* When a key is repeated, there will be two events: released, followed by another immediate pressed.
So check to see if another pressed is present */
if (!_patch_main_loop_real_XPending(display)) {
return false;
}
XEvent e;
XPeekEvent(display, &e);
if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode && (e.xkey.time - event->xkey.time) < 2) {
_patch_main_loop_real_XNextEvent(display, &e);
return true;
}
/* When a key is repeated, there will be two events: released, followed by
another immediate pressed. So check to see if another pressed is present */
if (!_patch_main_loop_real_XPending(display)) {
return false;
}
XEvent e;
XPeekEvent(display, &e);
if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode &&
(e.xkey.time - event->xkey.time) < 2) {
_patch_main_loop_real_XNextEvent(display, &e);
return true;
}
return false;
}
+15 -8
View File
@@ -36,24 +36,31 @@
#ifndef PATCH_MAIN_LOOP_H
#define PATCH_MAIN_LOOP_H
#include <stdbool.h>
#include <X11/Xutil.h>
#include <stdbool.h>
/**
* Initialize the patch module
*
* @param fix_sigalarm_main_loop True to enable the sigalarm thread fix (doc see above)
* @param disable_built_in_inputs Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)
* @param disable_mk3_linux_port_inputs Disable the built-in keyboard inputs on the MK3 linux ports
* @param fix_sigalarm_main_loop True to enable the sigalarm thread fix (doc see
* above)
* @param disable_built_in_inputs Disable the built in keyboard inputs for test
* (F1), service (F2) and clear (F3)
* @param disable_mk3_linux_port_inputs Disable the built-in keyboard inputs on
* the MK3 linux ports
*/
void patch_main_loop_init(bool fix_sigalarm_main_loop, bool disable_built_in_inputs,
void patch_main_loop_init(
bool fix_sigalarm_main_loop,
bool disable_built_in_inputs,
bool disable_mk3_linux_port_inputs);
/**
* Register a handler (multiple possible) to receive X11 input events, e.g. key pressed, released
* Register a handler (multiple possible) to receive X11 input events, e.g. key
* pressed, released
*
* @param lib_with_handler_impl Path to a library implementing the x11-input-handler API
* @param lib_with_handler_impl Path to a library implementing the
* x11-input-handler API
*/
void patch_main_loop_add_x11_input_handler(const char* lib_with_handler_impl);
void patch_main_loop_add_x11_input_handler(const char *lib_with_handler_impl);
#endif
+39 -42
View File
@@ -16,57 +16,54 @@ static int _patch_microdog34_fd = -1;
enum cnh_result patch_microdog34_iohook(struct cnh_iohook_irp *irp);
void patch_microdog34_init(const uint8_t* key_data, size_t len)
void patch_microdog34_init(const uint8_t *key_data, size_t len)
{
sec_microdog34_init(key_data, len);
sec_microdog34_init(key_data, len);
cnh_iohook_push_handler(patch_microdog34_iohook);
log_info("Initialized");
cnh_iohook_push_handler(patch_microdog34_iohook);
log_info("Initialized");
}
enum cnh_result patch_microdog34_iohook(struct cnh_iohook_irp *irp)
{
if (irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != _patch_microdog34_fd) {
return cnh_iohook_invoke_next(irp);
if (irp->op != CNH_IOHOOK_IRP_OP_OPEN && irp->fd != _patch_microdog34_fd) {
return cnh_iohook_invoke_next(irp);
}
switch (irp->op) {
case CNH_IOHOOK_IRP_OP_OPEN: {
if (!strcmp(irp->open_filename, USBDOG_ENDPOINT)) {
_patch_microdog34_fd = cnh_iohook_open_dummy_fd();
irp->fd = _patch_microdog34_fd;
return CNH_RESULT_SUCCESS;
}
return cnh_iohook_invoke_next(irp);
}
switch (irp->op) {
case CNH_IOHOOK_IRP_OP_OPEN:
{
if (!strcmp(irp->open_filename, USBDOG_ENDPOINT)) {
_patch_microdog34_fd = cnh_iohook_open_dummy_fd();
irp->fd = _patch_microdog34_fd;
return CNH_RESULT_SUCCESS;
}
case CNH_IOHOOK_IRP_OP_CLOSE: {
assert(irp->fd);
return cnh_iohook_invoke_next(irp);
}
cnh_iohook_close_dummy_fd(irp->fd);
_patch_microdog34_fd = -1;
case CNH_IOHOOK_IRP_OP_CLOSE:
{
assert(irp->fd);
cnh_iohook_close_dummy_fd(irp->fd);
_patch_microdog34_fd = -1;
return CNH_RESULT_SUCCESS;
}
case CNH_IOHOOK_IRP_OP_READ:
{
/* Just stub and return success */
return CNH_RESULT_SUCCESS;
}
case CNH_IOHOOK_IRP_OP_IOCTL:
{
irp->ioctl.pos = (size_t) sec_microdog34_process(irp->ioctl_req, irp->ioctl.bytes);
return CNH_RESULT_SUCCESS;
}
default:
log_die("Unhandled operation: %d", irp->op);
return CNH_RESULT_OTHER_ERROR;
return CNH_RESULT_SUCCESS;
}
case CNH_IOHOOK_IRP_OP_READ: {
/* Just stub and return success */
return CNH_RESULT_SUCCESS;
}
case CNH_IOHOOK_IRP_OP_IOCTL: {
irp->ioctl.pos =
(size_t) sec_microdog34_process(irp->ioctl_req, irp->ioctl.bytes);
return CNH_RESULT_SUCCESS;
}
default:
log_die("Unhandled operation: %d", irp->op);
return CNH_RESULT_OTHER_ERROR;
}
}
+1 -1
View File
@@ -10,6 +10,6 @@
* @param key_data Pointer to loaded key data (dog attributes, key table)
* @param len Length of the buffer
*/
void patch_microdog34_init(const uint8_t* key_data, size_t len);
void patch_microdog34_init(const uint8_t *key_data, size_t len);
#endif
+14 -14
View File
@@ -8,33 +8,33 @@
static pthread_t patch_microdog40_thread;
static void* patch_microdog40_thread_run(void* args)
static void *patch_microdog40_thread_run(void *args)
{
log_info("Running daemon thread");
log_info("Running daemon thread");
sec_microdog40d_run();
sec_microdog40d_run();
log_info("Finished daemon thread");
log_info("Finished daemon thread");
return NULL;
return NULL;
}
void patch_microdog40_init(const uint8_t* key_data, size_t len)
void patch_microdog40_init(const uint8_t *key_data, size_t len)
{
sec_microdog40d_init(key_data, len);
sec_microdog40d_init(key_data, len);
/* Run the daemon in another thread */
pthread_create(&patch_microdog40_thread, NULL,
patch_microdog40_thread_run, NULL);
/* Run the daemon in another thread */
pthread_create(
&patch_microdog40_thread, NULL, patch_microdog40_thread_run, NULL);
log_info("Initialized");
log_info("Initialized");
}
void patch_microdog40_shutdown(void)
{
log_info("Shutting down");
log_info("Shutting down");
sec_microdog40d_shutdown();
sec_microdog40d_shutdown();
pthread_join(patch_microdog40_thread, NULL);
pthread_join(patch_microdog40_thread, NULL);
}
+1 -1
View File
@@ -10,7 +10,7 @@
* @param key_data Pointer to loaded key data (dog attributes, key table)
* @param len Length of the buffer
*/
void patch_microdog40_init(const uint8_t* key_data, size_t len);
void patch_microdog40_init(const uint8_t *key_data, size_t len);
/**
* Shutdown and remove the emulator
+65 -70
View File
@@ -10,96 +10,91 @@
#include "util/log.h"
/* looks odd but hddd is intentional */
static const char* patch_mount_proc_mount_file = "/dev/hddd /mnt/hd";
static const char *patch_mount_proc_mount_file = "/dev/hddd /mnt/hd";
static FILE* patch_mount_file = NULL;
static FILE *patch_mount_file = NULL;
static bool patch_mount_eof;
static enum cnh_result patch_hdd_check_filehook(struct cnh_filehook_irp *irp)
{
enum cnh_result result;
enum cnh_result result;
result = CNH_RESULT_SUCCESS;
result = CNH_RESULT_SUCCESS;
assert(irp);
assert(irp);
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != patch_mount_file) {
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != patch_mount_file) {
return cnh_filehook_invoke_next(irp);
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN: {
if (!strcmp(irp->open_filename, "/proc/mounts")) {
patch_mount_file = cnh_filehook_open_dummy_file_handle();
irp->file = patch_mount_file;
patch_mount_eof = false;
log_debug("/proc/mounts opened: %p", irp->file);
} else {
return cnh_filehook_invoke_next(irp);
}
break;
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN:
{
if (!strcmp(irp->open_filename, "/proc/mounts")) {
patch_mount_file = cnh_filehook_open_dummy_file_handle();
irp->file = patch_mount_file;
case CNH_FILEHOOK_IRP_OP_FGETS: {
size_t size;
patch_mount_eof = false;
log_info("/proc/mounts fake read");
log_debug("/proc/mounts opened: %p", irp->file);
} else {
return cnh_filehook_invoke_next(irp);
}
size = strlen(patch_mount_proc_mount_file) + 1;
break;
}
/* +1: copy the null terminator, too */
memcpy(
&irp->read.bytes[irp->read.pos], patch_mount_proc_mount_file, size);
irp->read.pos += size;
case CNH_FILEHOOK_IRP_OP_FGETS:
{
size_t size;
patch_mount_eof = true;
log_info("/proc/mounts fake read");
size = strlen(patch_mount_proc_mount_file) + 1;
/* +1: copy the null terminator, too */
memcpy(&irp->read.bytes[irp->read.pos], patch_mount_proc_mount_file, size);
irp->read.pos += size;
patch_mount_eof = true;
break;
}
case CNH_FILEHOOK_IRP_OP_SEEK:
{
/* Ignore seeking */
break;
}
case CNH_FILEHOOK_IRP_OP_TELL:
{
/* Return size */
irp->tell_offset = strlen(patch_mount_proc_mount_file) + 1;
break;
}
case CNH_FILEHOOK_IRP_OP_EOF:
{
irp->eof = patch_mount_eof;
break;
}
case CNH_FILEHOOK_IRP_OP_CLOSE:
{
patch_mount_file = NULL;
/* Actually close dummy handle */
return cnh_filehook_invoke_next(irp);
}
default:
log_warn("Unhandled file op: %d", irp->op);
break;
break;
}
return result;
case CNH_FILEHOOK_IRP_OP_SEEK: {
/* Ignore seeking */
break;
}
case CNH_FILEHOOK_IRP_OP_TELL: {
/* Return size */
irp->tell_offset = strlen(patch_mount_proc_mount_file) + 1;
break;
}
case CNH_FILEHOOK_IRP_OP_EOF: {
irp->eof = patch_mount_eof;
break;
}
case CNH_FILEHOOK_IRP_OP_CLOSE: {
patch_mount_file = NULL;
/* Actually close dummy handle */
return cnh_filehook_invoke_next(irp);
}
default:
log_warn("Unhandled file op: %d", irp->op);
break;
}
return result;
}
void patch_mounts_init(void)
{
cnh_filehook_push_handler(patch_hdd_check_filehook);
log_info("Initialized");
cnh_filehook_push_handler(patch_hdd_check_filehook);
log_info("Initialized");
}
File diff suppressed because it is too large Load Diff
+11 -9
View File
@@ -1,5 +1,6 @@
/**
* Patch module to redirect profile saving and loading to a pumpnet server (NX2 to Fiesta 2).
* Patch module to redirect profile saving and loading to a pumpnet server (NX2
* to Fiesta 2).
*/
#ifndef HOOK_PATCH_NET_PROFILE_H
#define HOOK_PATCH_NET_PROFILE_H
@@ -12,16 +13,17 @@
* @param game Game version to run this module on
* @param pumpnet_server_addr Server address of pumpnet to connect to
* @param machine_id Machine ID to use for authentication
* @param cert_dir_path Path to a directory containing the client cert, client key and CA cert bundle to enable https
* communication
* @param verbose_debug_log Enable verbose debug log output, e.g. network backend logging/traffic.
* @param cert_dir_path Path to a directory containing the client cert, client
* key and CA cert bundle to enable https communication
* @param verbose_debug_log Enable verbose debug log output, e.g. network
* backend logging/traffic.
*/
void patch_net_profile_init(
enum asset_game_version game,
const char* pumpnet_server_addr,
uint64_t machine_id,
const char* cert_dir_path,
bool verbose_debug_log);
enum asset_game_version game,
const char *pumpnet_server_addr,
uint64_t machine_id,
const char *cert_dir_path,
bool verbose_debug_log);
/**
* Shut down the module.
+65 -53
View File
@@ -1,7 +1,7 @@
#define LOG_MODULE "patch-network"
#include <string.h>
#include <arpa/inet.h>
#include <string.h>
#include "capnhook/hook/lib.h"
@@ -11,13 +11,14 @@
#include "util/str.h"
struct patch_network_redirect_elem {
struct util_list_node head;
char* orig_ipv4;
char* new_ipv4;
uint16_t new_port;
struct util_list_node head;
char *orig_ipv4;
char *new_ipv4;
uint16_t new_port;
};
typedef int (*connect_t) (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
typedef int (*connect_t)(
int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
static connect_t patch_network_real_connect;
@@ -26,71 +27,82 @@ static struct util_list patch_network_redirect_list;
int connect(int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
{
if (!patch_network_real_connect) {
patch_network_real_connect = (connect_t) cnh_lib_get_func_addr("connect");
}
if (!patch_network_real_connect) {
patch_network_real_connect = (connect_t) cnh_lib_get_func_addr("connect");
}
if (patch_network_initialized) {
if (addr.__sockaddr__->sa_family == AF_INET) {
log_debug("connect ipv4 %d.%d.%d.%d:%d",
addr.__sockaddr_in__->sin_addr.s_addr & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 8 & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 16 & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 24 & 0xFF,
addr.__sockaddr_in__->sin_port);
if (patch_network_initialized) {
if (addr.__sockaddr__->sa_family == AF_INET) {
log_debug(
"connect ipv4 %d.%d.%d.%d:%d",
addr.__sockaddr_in__->sin_addr.s_addr & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 8 & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 16 & 0xFF,
addr.__sockaddr_in__->sin_addr.s_addr >> 24 & 0xFF,
addr.__sockaddr_in__->sin_port);
struct util_list_node* pos;
struct patch_network_redirect_elem* elem;
struct sockaddr_in tmp;
struct util_list_node *pos;
struct patch_network_redirect_elem *elem;
struct sockaddr_in tmp;
for (pos = patch_network_redirect_list.head; pos != NULL; pos = pos->next) {
elem = containerof(pos, struct patch_network_redirect_elem, head);
for (pos = patch_network_redirect_list.head; pos != NULL;
pos = pos->next) {
elem = containerof(pos, struct patch_network_redirect_elem, head);
inet_aton(elem->orig_ipv4, &tmp.sin_addr);
inet_aton(elem->orig_ipv4, &tmp.sin_addr);
if (addr.__sockaddr_in__->sin_addr.s_addr == tmp.sin_addr.s_addr) {
char* tmp_old = inet_ntoa(addr.__sockaddr_in__->sin_addr);
log_info("Redirect %s:%d -> %s:%d", tmp_old,
((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port, elem->new_ipv4,
elem->new_port != 0xFFFF ? elem->new_port :
((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port);
if (addr.__sockaddr_in__->sin_addr.s_addr == tmp.sin_addr.s_addr) {
char *tmp_old = inet_ntoa(addr.__sockaddr_in__->sin_addr);
log_info(
"Redirect %s:%d -> %s:%d",
tmp_old,
((struct sockaddr_in *) addr.__sockaddr_in__)->sin_port,
elem->new_ipv4,
elem->new_port != 0xFFFF ?
elem->new_port :
((struct sockaddr_in *) addr.__sockaddr_in__)->sin_port);
inet_aton(elem->new_ipv4, &((struct sockaddr_in*) addr.__sockaddr_in__)->sin_addr);
inet_aton(
elem->new_ipv4,
&((struct sockaddr_in *) addr.__sockaddr_in__)->sin_addr);
if (elem->new_port != 0xFFFF) {
((struct sockaddr_in*) addr.__sockaddr_in__)->sin_port = htons(elem->new_port);
}
}
}
} else {
log_debug("connect, addr family: %d", addr.__sockaddr__->sa_family);
if (elem->new_port != 0xFFFF) {
((struct sockaddr_in *) addr.__sockaddr_in__)->sin_port =
htons(elem->new_port);
}
}
}
} else {
log_debug("connect, addr family: %d", addr.__sockaddr__->sa_family);
}
}
return patch_network_real_connect(fd, addr, len);
return patch_network_real_connect(fd, addr, len);
}
void patch_network_init()
{
util_list_init(&patch_network_redirect_list);
patch_network_initialized = true;
log_info("Initialized");
util_list_init(&patch_network_redirect_list);
patch_network_initialized = true;
log_info("Initialized");
}
void patch_network_redirect_server_address(const char* orig_ipv4, const char* new_ipv4, uint16_t new_port)
void patch_network_redirect_server_address(
const char *orig_ipv4, const char *new_ipv4, uint16_t new_port)
{
struct patch_network_redirect_elem* elem;
struct patch_network_redirect_elem *elem;
elem = util_xmalloc(sizeof(struct patch_network_redirect_elem));
elem->orig_ipv4 = util_str_dup(orig_ipv4);
elem->new_ipv4 = util_str_dup(new_ipv4);
elem->new_port = new_port;
elem = util_xmalloc(sizeof(struct patch_network_redirect_elem));
elem->orig_ipv4 = util_str_dup(orig_ipv4);
elem->new_ipv4 = util_str_dup(new_ipv4);
elem->new_port = new_port;
util_list_append(&patch_network_redirect_list, &elem->head);
util_list_append(&patch_network_redirect_list, &elem->head);
if (new_port != 0xFFFF) {
log_info("Add network redirect: %s -> %s:%d", orig_ipv4, new_ipv4, new_port);
} else {
log_info("Add network redirect: %s -> %s", orig_ipv4, new_ipv4);
}
if (new_port != 0xFFFF) {
log_info(
"Add network redirect: %s -> %s:%d", orig_ipv4, new_ipv4, new_port);
} else {
log_info("Add network redirect: %s -> %s", orig_ipv4, new_ipv4);
}
}
+2 -1
View File
@@ -18,6 +18,7 @@ void patch_network_init();
* @param new_ipv4 IPV4 address of the new server to redirect to
* @param new_port Port of server to redirect to (-1 to keep old port)
*/
void patch_network_redirect_server_address(const char* orig_ipv4, const char* new_ipv4, uint16_t new_port);
void patch_network_redirect_server_address(
const char *orig_ipv4, const char *new_ipv4, uint16_t new_port);
#endif
+200 -174
View File
@@ -17,12 +17,17 @@
static bool _patch_piubtn_enumerate(bool real_exists);
static enum cnh_result _patch_piubtn_open(void);
static enum cnh_result _patch_piubtn_reset(void);
static enum cnh_result _patch_piubtn_control_msg(int request_type, int request, int value, int index,
struct cnh_iobuf* buffer, int timeout);
static enum cnh_result _patch_piubtn_control_msg(
int request_type,
int request,
int value,
int index,
struct cnh_iobuf *buffer,
int timeout);
static void _patch_piubtn_close(void);
static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf* buffer);
static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf* buffer);
static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf *buffer);
static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf *buffer);
static ptapi_io_piubtn_ident_t _patch_piubtn_ptapi_io_piubtn_ident;
static ptapi_io_piubtn_open_t _patch_piubtn_ptapi_io_piubtn_open;
@@ -42,251 +47,272 @@ static const struct cnh_usb_emu_virtdev_ep _patch_piubtn_virtdev = {
.close = _patch_piubtn_close,
};
static void* _patch_piubtn_api_lib_handle;
static void *_patch_piubtn_api_lib_handle;
void patch_piubtn_init(const char* piubtn_lib_path)
void patch_piubtn_init(const char *piubtn_lib_path)
{
if (!piubtn_lib_path) {
log_die("No piubtn emulation library path specified");
}
if (!piubtn_lib_path) {
log_die("No piubtn emulation library path specified");
}
/* Load piubtn library funcs */
log_info("Loading piubtn api implementation %s", piubtn_lib_path);
/* Load piubtn library funcs */
log_info("Loading piubtn api implementation %s", piubtn_lib_path);
_patch_piubtn_api_lib_handle = cnh_lib_load(piubtn_lib_path);
_patch_piubtn_api_lib_handle = cnh_lib_load(piubtn_lib_path);
_patch_piubtn_ptapi_io_piubtn_ident = (ptapi_io_piubtn_ident_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_ident");
_patch_piubtn_ptapi_io_piubtn_ident =
(ptapi_io_piubtn_ident_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_ident");
_patch_piubtn_ptapi_io_piubtn_open = (ptapi_io_piubtn_open_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_open");
_patch_piubtn_ptapi_io_piubtn_close = (ptapi_io_piubtn_close_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_close");
_patch_piubtn_ptapi_io_piubtn_recv = (ptapi_io_piubtn_recv_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_recv");
_patch_piubtn_ptapi_io_piubtn_send = (ptapi_io_piubtn_send_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_send");
_patch_piubtn_ptapi_io_piubtn_get_input = (ptapi_io_piubtn_get_input_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_get_input");
_patch_piubtn_ptapi_io_piubtn_set_output = (ptapi_io_piubtn_set_output_t)
cnh_lib_get_func_addr_handle(_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_set_output");
_patch_piubtn_ptapi_io_piubtn_open =
(ptapi_io_piubtn_open_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_open");
_patch_piubtn_ptapi_io_piubtn_close =
(ptapi_io_piubtn_close_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_close");
_patch_piubtn_ptapi_io_piubtn_recv =
(ptapi_io_piubtn_recv_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_recv");
_patch_piubtn_ptapi_io_piubtn_send =
(ptapi_io_piubtn_send_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_send");
_patch_piubtn_ptapi_io_piubtn_get_input =
(ptapi_io_piubtn_get_input_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_get_input");
_patch_piubtn_ptapi_io_piubtn_set_output =
(ptapi_io_piubtn_set_output_t) cnh_lib_get_func_addr_handle(
_patch_piubtn_api_lib_handle, "ptapi_io_piubtn_set_output");
cnh_usb_emu_add_virtdevep(&_patch_piubtn_virtdev);
cnh_usb_emu_add_virtdevep(&_patch_piubtn_virtdev);
log_info("Initialized");
log_info("Initialized");
}
void patch_piubtn_shutdown(void)
{
}
static bool _patch_piubtn_enumerate(bool real_exists)
{
if (real_exists) {
log_info("Real PIUBTN exists but emulation enabled, blocking real");
} else {
log_info("Enumerating PIUBTN emulation");
}
if (real_exists) {
log_info("Real PIUBTN exists but emulation enabled, blocking real");
} else {
log_info("Enumerating PIUBTN emulation");
}
return true;
return true;
}
static enum cnh_result _patch_piubtn_open(void)
{
log_info("Opening PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
log_info("Opening PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
if (!_patch_piubtn_ptapi_io_piubtn_open()) {
log_error("Opening api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piubtn_ptapi_io_piubtn_open()) {
log_error(
"Opening api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
return CNH_RESULT_SUCCESS;
return CNH_RESULT_SUCCESS;
}
static enum cnh_result _patch_piubtn_reset(void)
{
log_info("Resetting PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
log_info("Resetting PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
_patch_piubtn_ptapi_io_piubtn_close();
_patch_piubtn_ptapi_io_piubtn_close();
if (!_patch_piubtn_ptapi_io_piubtn_open()) {
log_error("Resetting api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piubtn_ptapi_io_piubtn_open()) {
log_error(
"Resetting api piubtn %s failed",
_patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
return CNH_RESULT_SUCCESS;
return CNH_RESULT_SUCCESS;
}
static enum cnh_result _patch_piubtn_control_msg(int request_type, int request, int value, int index,
struct cnh_iobuf* buffer, int timeout)
static enum cnh_result _patch_piubtn_control_msg(
int request_type,
int request,
int value,
int index,
struct cnh_iobuf *buffer,
int timeout)
{
if (request_type == PIUBTN_DRV_USB_CTRL_TYPE_IN && request == PIUBTN_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
return _patch_piubtn_process_inputs(buffer);
} else if (request_type == PIUBTN_DRV_USB_CTRL_TYPE_OUT && request == PIUBTN_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
return _patch_piubtn_process_outputs(buffer);
} else {
log_error("Invalid usb control request to PIUBTN: 0x%02X", request);
return CNH_RESULT_INVALID_PARAMETER;
if (request_type == PIUBTN_DRV_USB_CTRL_TYPE_IN &&
request == PIUBTN_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
return _patch_piubtn_process_inputs(buffer);
} else if (
request_type == PIUBTN_DRV_USB_CTRL_TYPE_OUT &&
request == PIUBTN_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUBTN_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
return _patch_piubtn_process_outputs(buffer);
} else {
log_error("Invalid usb control request to PIUBTN: 0x%02X", request);
return CNH_RESULT_INVALID_PARAMETER;
}
}
static void _patch_piubtn_close(void)
{
log_info("Closing PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
log_info("Closing PIUBTN: %s", _patch_piubtn_ptapi_io_piubtn_ident());
_patch_piubtn_ptapi_io_piubtn_close();
_patch_piubtn_ptapi_io_piubtn_close();
}
static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf* buffer)
static enum cnh_result _patch_piubtn_process_inputs(struct cnh_iobuf *buffer)
{
struct ptapi_io_piubtn_inputs p1;
struct ptapi_io_piubtn_inputs p2;
struct ptapi_io_piubtn_inputs p1;
struct ptapi_io_piubtn_inputs p2;
if (!_patch_piubtn_ptapi_io_piubtn_recv()) {
log_error("Receiving inputs on api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piubtn_ptapi_io_piubtn_recv()) {
log_error(
"Receiving inputs on api piubtn %s failed",
_patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
memset(&p1, 0, sizeof(p1));
memset(&p2, 0, sizeof(p2));
memset(&p1, 0, sizeof(p1));
memset(&p2, 0, sizeof(p2));
_patch_piubtn_ptapi_io_piubtn_get_input(0, &p1);
_patch_piubtn_ptapi_io_piubtn_get_input(1, &p2);
_patch_piubtn_ptapi_io_piubtn_get_input(0, &p1);
_patch_piubtn_ptapi_io_piubtn_get_input(1, &p2);
memset(buffer->bytes, 0, PIUBTN_DRV_BUFFER_SIZE);
memset(buffer->bytes, 0, PIUBTN_DRV_BUFFER_SIZE);
/*
byte 0:
bit 0: P1 back (red)
bit 1: P1 left
bit 2: P1 right
bit 3: P1 start (green)
bit 4: P2 back (red)
bit 5: P2 left
bit 6: P2 right
bit 7: P2 start (green)
*/
/*
byte 0:
bit 0: P1 back (red)
bit 1: P1 left
bit 2: P1 right
bit 3: P1 start (green)
bit 4: P2 back (red)
bit 5: P2 left
bit 6: P2 right
bit 7: P2 start (green)
*/
/* Player 1 */
if (p1.back) {
buffer->bytes[0] |= (1 << 0);
}
/* Player 1 */
if (p1.back) {
buffer->bytes[0] |= (1 << 0);
}
if (p1.left) {
buffer->bytes[0] |= (1 << 1);
}
if (p1.left) {
buffer->bytes[0] |= (1 << 1);
}
if (p1.right) {
buffer->bytes[0] |= (1 << 2);
}
if (p1.right) {
buffer->bytes[0] |= (1 << 2);
}
if (p1.start) {
buffer->bytes[0] |= (1 << 3);
}
if (p1.start) {
buffer->bytes[0] |= (1 << 3);
}
/* Player 2 */
if (p2.back) {
buffer->bytes[0] |= (1 << 4);
}
/* Player 2 */
if (p2.back) {
buffer->bytes[0] |= (1 << 4);
}
if (p2.left) {
buffer->bytes[0] |= (1 << 5);
}
if (p2.left) {
buffer->bytes[0] |= (1 << 5);
}
if (p2.right) {
buffer->bytes[0] |= (1 << 6);
}
if (p2.right) {
buffer->bytes[0] |= (1 << 6);
}
if (p2.start) {
buffer->bytes[0] |= (1 << 7);
}
if (p2.start) {
buffer->bytes[0] |= (1 << 7);
}
/* xor inputs because pullup active */
for (int i = 0; i < PIUBTN_DRV_BUFFER_SIZE; i++) {
buffer->bytes[i] ^= 0xFF;
}
/* xor inputs because pullup active */
for (int i = 0; i < PIUBTN_DRV_BUFFER_SIZE; i++) {
buffer->bytes[i] ^= 0xFF;
}
buffer->pos = PIUBTN_DRV_BUFFER_SIZE;
buffer->pos = PIUBTN_DRV_BUFFER_SIZE;
return CNH_RESULT_SUCCESS;
return CNH_RESULT_SUCCESS;
}
static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf* buffer)
static enum cnh_result _patch_piubtn_process_outputs(struct cnh_iobuf *buffer)
{
struct ptapi_io_piubtn_outputs p1;
struct ptapi_io_piubtn_outputs p2;
struct ptapi_io_piubtn_outputs p1;
struct ptapi_io_piubtn_outputs p2;
memset(&p1, 0, sizeof(p1));
memset(&p2, 0, sizeof(p2));
memset(&p1, 0, sizeof(p1));
memset(&p2, 0, sizeof(p2));
/*
byte 0:
bit 0: p1 start (green)
bit 1: p1 right
bit 2: p1 left
bit 3: p1 back (red)
bit 4: p2 start (green)
bit 5: p2 right
bit 6: p2 left
bit 7: p2 back (red)
*/
/*
byte 0:
bit 0: p1 start (green)
bit 1: p1 right
bit 2: p1 left
bit 3: p1 back (red)
bit 4: p2 start (green)
bit 5: p2 right
bit 6: p2 left
bit 7: p2 back (red)
*/
/* Player 1 */
/* Player 1 */
if (buffer->bytes[0] & (1 << 0)) {
p1.start = true;
}
if (buffer->bytes[0] & (1 << 0)) {
p1.start = true;
}
if (buffer->bytes[0] & (1 << 1)) {
p1.back = true;
}
if (buffer->bytes[0] & (1 << 1)) {
p1.back = true;
}
if (buffer->bytes[0] & (1 << 2)) {
p1.left = true;
}
if (buffer->bytes[0] & (1 << 2)) {
p1.left = true;
}
if (buffer->bytes[0] & (1 << 3)) {
p1.right = true;
}
if (buffer->bytes[0] & (1 << 3)) {
p1.right = true;
}
/* Player 2 */
/* Player 2 */
if (buffer->bytes[0] & (1 << 4)) {
p2.start = true;
}
if (buffer->bytes[0] & (1 << 4)) {
p2.start = true;
}
if (buffer->bytes[0] & (1 << 5)) {
p2.right = true;
}
if (buffer->bytes[0] & (1 << 5)) {
p2.right = true;
}
if (buffer->bytes[0] & (1 << 6)) {
p2.left = true;
}
if (buffer->bytes[0] & (1 << 6)) {
p2.left = true;
}
if (buffer->bytes[0] & (1 << 7)) {
p2.back = true;
}
if (buffer->bytes[0] & (1 << 7)) {
p2.back = true;
}
_patch_piubtn_ptapi_io_piubtn_set_output(0, &p1);
_patch_piubtn_ptapi_io_piubtn_set_output(1, &p2);
_patch_piubtn_ptapi_io_piubtn_set_output(0, &p1);
_patch_piubtn_ptapi_io_piubtn_set_output(1, &p2);
if (!_patch_piubtn_ptapi_io_piubtn_send()) {
log_error("Sending outputs on api piubtn %s failed", _patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piubtn_ptapi_io_piubtn_send()) {
log_error(
"Sending outputs on api piubtn %s failed",
_patch_piubtn_ptapi_io_piubtn_ident());
return CNH_RESULT_OTHER_ERROR;
}
buffer->pos = PIUBTN_DRV_BUFFER_SIZE;
buffer->pos = PIUBTN_DRV_BUFFER_SIZE;
return CNH_RESULT_SUCCESS;
return CNH_RESULT_SUCCESS;
}
+5 -3
View File
@@ -15,14 +15,16 @@
* @param piubtn_lib_path Path to a library implementing the piubtn API
* @param real_passthrough True to ignore the library and disable any emulation
*/
void patch_piubtn_init(const char* piubtn_lib_path);
void patch_piubtn_init(const char *piubtn_lib_path);
/**
* Get the input hook handler provided by the piubtn library.
*
* @return Input hook handler for main-loop patch module or NULL if none is used.
* @return Input hook handler for main-loop patch module or NULL if none is
* used.
*/
const struct pumptools_input_hook_handler* patch_piubtn_get_input_hook_handler(void);
const struct pumptools_input_hook_handler *
patch_piubtn_get_input_hook_handler(void);
/**
* Shut down the patch module
+65 -64
View File
@@ -7,83 +7,84 @@
static enum cnh_result patch_piuio_exit_usbhook(struct cnh_usbhook_irp *irp);
static usb_dev_handle* _patch_piuio_exit_usb_handle;
static usb_dev_handle *_patch_piuio_exit_usb_handle;
void patch_piuio_exit_init()
{
cnh_usbhook_push_handler(patch_piuio_exit_usbhook);
log_info("Initialized");
cnh_usbhook_push_handler(patch_piuio_exit_usbhook);
log_info("Initialized");
}
static enum cnh_result patch_piuio_exit_usbhook(struct cnh_usbhook_irp *irp)
{
enum cnh_result result;
enum cnh_result result;
if (irp->op != CNH_USBHOOK_IRP_OP_OPEN && _patch_piuio_exit_usb_handle != irp->handle) {
return cnh_usbhook_invoke_next(irp);
if (irp->op != CNH_USBHOOK_IRP_OP_OPEN &&
_patch_piuio_exit_usb_handle != irp->handle) {
return cnh_usbhook_invoke_next(irp);
}
switch (irp->op) {
case CNH_USBHOOK_IRP_OP_OPEN: {
if (irp->open_usb_dev->descriptor.idVendor == PIUIO_DRV_VID &&
irp->open_usb_dev->descriptor.idProduct == PIUIO_DRV_PID) {
if (_patch_piuio_exit_usb_handle) {
log_warn("Already detected PIUIO previously, ignore re-detection?");
irp->handle = _patch_piuio_exit_usb_handle;
result = CNH_RESULT_SUCCESS;
} else {
log_info("Detected PIUIO");
result = cnh_usbhook_invoke_next(irp);
if (result == CNH_RESULT_SUCCESS) {
_patch_piuio_exit_usb_handle = irp->handle;
}
}
} else {
result = cnh_usbhook_invoke_next(irp);
}
break;
}
switch (irp->op) {
case CNH_USBHOOK_IRP_OP_OPEN:
{
if (irp->open_usb_dev->descriptor.idVendor == PIUIO_DRV_VID &&
irp->open_usb_dev->descriptor.idProduct == PIUIO_DRV_PID) {
case CNH_USBHOOK_IRP_OP_CTRL_MSG: {
result = cnh_usbhook_invoke_next(irp);
if (_patch_piuio_exit_usb_handle) {
log_warn("Already detected PIUIO previously, ignore re-detection?");
irp->handle = _patch_piuio_exit_usb_handle;
result = CNH_RESULT_SUCCESS;
} else {
log_info("Detected PIUIO");
result = cnh_usbhook_invoke_next(irp);
if (result == CNH_RESULT_SUCCESS) {
_patch_piuio_exit_usb_handle = irp->handle;
}
}
} else {
result = cnh_usbhook_invoke_next(irp);
}
break;
/* Post process inputs */
if (irp->ctrl_req_type == PIUIO_DRV_USB_CTRL_TYPE_IN &&
irp->ctrl_req == PIUIO_DRV_USB_CTRL_REQUEST) {
if (irp->ctrl_buffer.nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error(
"Invalid buffer size for ctrl in: %d", irp->ctrl_buffer.nbytes);
} else {
/* Service + Test button pressed */
/* Invert data -> pull up active */
if (((~irp->ctrl_buffer.bytes[1]) & (1 << 1)) &&
((~irp->ctrl_buffer.bytes[1]) & (1 << 6))) {
log_info("Exit on service + test enabled and hit, bye");
exit(0);
}
}
}
case CNH_USBHOOK_IRP_OP_CTRL_MSG:
{
result = cnh_usbhook_invoke_next(irp);
/* Post process inputs */
if (irp->ctrl_req_type == PIUIO_DRV_USB_CTRL_TYPE_IN && irp->ctrl_req == PIUIO_DRV_USB_CTRL_REQUEST) {
if (irp->ctrl_buffer.nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl in: %d", irp->ctrl_buffer.nbytes);
} else {
/* Service + Test button pressed */
/* Invert data -> pull up active */
if (((~irp->ctrl_buffer.bytes[1]) & (1 << 1)) && ((~irp->ctrl_buffer.bytes[1]) & (1 << 6))) {
log_info("Exit on service + test enabled and hit, bye");
exit(0);
}
}
}
break;
}
case CNH_USBHOOK_IRP_OP_CLOSE:
{
_patch_piuio_exit_usb_handle = NULL;
result = cnh_usbhook_invoke_next(irp);
break;
}
default:
result = cnh_usbhook_invoke_next(irp);
break;
break;
}
return result;
case CNH_USBHOOK_IRP_OP_CLOSE: {
_patch_piuio_exit_usb_handle = NULL;
result = cnh_usbhook_invoke_next(irp);
break;
}
default:
result = cnh_usbhook_invoke_next(irp);
break;
}
return result;
}
+2 -1
View File
@@ -1,5 +1,6 @@
/**
* Patch module to allow exiting the game using the PIUIO, e.g. pressing service + test.
* Patch module to allow exiting the game using the PIUIO, e.g. pressing service
* + test.
*/
#ifndef PATCH_PIUIO_EXIT_H
#define PATCH_PIUIO_EXIT_H
+99 -91
View File
@@ -11,122 +11,130 @@
static enum cnh_result patch_piuio_khack_usbhook(struct cnh_usbhook_irp *irp);
static usb_dev_handle* _patch_piuio_khack_usb_handle;
static usb_dev_handle *_patch_piuio_khack_usb_handle;
void patch_piuio_khack_init()
{
cnh_usbhook_push_handler(patch_piuio_khack_usbhook);
log_info("Initialized");
cnh_usbhook_push_handler(patch_piuio_khack_usbhook);
log_info("Initialized");
}
static enum cnh_result patch_piuio_khack_usbhook(struct cnh_usbhook_irp *irp)
{
enum cnh_result result;
uint8_t out_buffer[PATCH_PIUIO_KHACK_BUFFER_SIZE];
uint8_t in_buffer[PATCH_PIUIO_KHACK_BUFFER_SIZE];
enum cnh_result result;
uint8_t out_buffer[PATCH_PIUIO_KHACK_BUFFER_SIZE];
uint8_t in_buffer[PATCH_PIUIO_KHACK_BUFFER_SIZE];
if (irp->op != CNH_USBHOOK_IRP_OP_OPEN && _patch_piuio_khack_usb_handle != irp->handle) {
return cnh_usbhook_invoke_next(irp);
if (irp->op != CNH_USBHOOK_IRP_OP_OPEN &&
_patch_piuio_khack_usb_handle != irp->handle) {
return cnh_usbhook_invoke_next(irp);
}
switch (irp->op) {
case CNH_USBHOOK_IRP_OP_OPEN: {
if (irp->open_usb_dev->descriptor.idVendor == PIUIO_DRV_VID &&
irp->open_usb_dev->descriptor.idProduct == PIUIO_DRV_PID) {
if (_patch_piuio_khack_usb_handle) {
log_warn("Already detected PIUIO previously, ignoring re-detection");
irp->handle = _patch_piuio_khack_usb_handle;
result = CNH_RESULT_SUCCESS;
} else {
log_info("Detected PIUIO");
result = cnh_usbhook_invoke_next(irp);
if (result == CNH_RESULT_SUCCESS) {
_patch_piuio_khack_usb_handle = irp->handle;
}
}
} else {
result = cnh_usbhook_invoke_next(irp);
}
break;
}
switch (irp->op) {
case CNH_USBHOOK_IRP_OP_OPEN:
{
if (irp->open_usb_dev->descriptor.idVendor == PIUIO_DRV_VID &&
irp->open_usb_dev->descriptor.idProduct == PIUIO_DRV_PID) {
case CNH_USBHOOK_IRP_OP_CTRL_MSG: {
// Identifiers for custom kernel hack introduced by some update in ITG 2
// back in the days
if (irp->ctrl_req_type == PATCH_PIUIO_KHACK_CTRL_REQ_TYPE &&
irp->ctrl_req == PATCH_PIUIO_KHACK_CTRL_REQ &&
irp->ctrl_timeout == PATCH_PIUIO_KHACK_TIMEOUT) {
if (_patch_piuio_khack_usb_handle) {
log_warn("Already detected PIUIO previously, ignoring re-detection");
irp->handle = _patch_piuio_khack_usb_handle;
result = CNH_RESULT_SUCCESS;
} else {
log_info("Detected PIUIO");
result = cnh_usbhook_invoke_next(irp);
if (result == CNH_RESULT_SUCCESS) {
_patch_piuio_khack_usb_handle = irp->handle;
}
}
} else {
result = cnh_usbhook_invoke_next(irp);
}
break;
// Hack combines the four calls for each sensor into a single call
if (irp->ctrl_buffer.nbytes != PATCH_PIUIO_KHACK_BUFFER_SIZE) {
log_error(
"Invalid buffer size for kernel hack: %d",
irp->ctrl_buffer.nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
case CNH_USBHOOK_IRP_OP_CTRL_MSG:
{
// Identifiers for custom kernel hack introduced by some update in ITG 2 back in the days
if (irp->ctrl_req_type == PATCH_PIUIO_KHACK_CTRL_REQ_TYPE &&
irp->ctrl_req == PATCH_PIUIO_KHACK_CTRL_REQ &&
irp->ctrl_timeout == PATCH_PIUIO_KHACK_TIMEOUT) {
memcpy(out_buffer, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes);
// Hack combines the four calls for each sensor into a single call
if (irp->ctrl_buffer.nbytes != PATCH_PIUIO_KHACK_BUFFER_SIZE) {
log_error("Invalid buffer size for kernel hack: %d", irp->ctrl_buffer.nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
// Split the hack into single calls
for (uint8_t i = 0; i < 4; i++) {
irp->ctrl_req_type = PIUIO_DRV_USB_CTRL_TYPE_OUT;
irp->ctrl_req = PIUIO_DRV_USB_CTRL_REQUEST;
irp->ctrl_timeout = PIUIO_DRV_USB_REQ_TIMEOUT;
irp->ctrl_buffer.pos = 0;
irp->ctrl_buffer.nbytes = PIUIO_DRV_BUFFER_SIZE;
memcpy(out_buffer, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes);
memcpy(
irp->ctrl_buffer.bytes,
&out_buffer[PIUIO_DRV_BUFFER_SIZE * i],
PIUIO_DRV_BUFFER_SIZE);
// Split the hack into single calls
for (uint8_t i = 0; i < 4; i++) {
irp->ctrl_req_type = PIUIO_DRV_USB_CTRL_TYPE_OUT;
irp->ctrl_req = PIUIO_DRV_USB_CTRL_REQUEST;
irp->ctrl_timeout = PIUIO_DRV_USB_REQ_TIMEOUT;
irp->ctrl_buffer.pos = 0;
irp->ctrl_buffer.nbytes = PIUIO_DRV_BUFFER_SIZE;
result = cnh_usbhook_invoke_next_reset_advance(irp);
memcpy(irp->ctrl_buffer.bytes, &out_buffer[PIUIO_DRV_BUFFER_SIZE * i], PIUIO_DRV_BUFFER_SIZE);
if (result != CNH_RESULT_SUCCESS) {
return result;
}
result = cnh_usbhook_invoke_next_reset_advance(irp);
irp->ctrl_req_type = PIUIO_DRV_USB_CTRL_TYPE_IN;
irp->ctrl_req = PIUIO_DRV_USB_CTRL_REQUEST;
irp->ctrl_timeout = PIUIO_DRV_USB_REQ_TIMEOUT;
irp->ctrl_buffer.pos = 0;
irp->ctrl_buffer.nbytes = PIUIO_DRV_BUFFER_SIZE;
if (result != CNH_RESULT_SUCCESS) {
return result;
}
result = cnh_usbhook_invoke_next_reset_advance(irp);
irp->ctrl_req_type = PIUIO_DRV_USB_CTRL_TYPE_IN;
irp->ctrl_req = PIUIO_DRV_USB_CTRL_REQUEST;
irp->ctrl_timeout = PIUIO_DRV_USB_REQ_TIMEOUT;
irp->ctrl_buffer.pos = 0;
irp->ctrl_buffer.nbytes = PIUIO_DRV_BUFFER_SIZE;
if (result != CNH_RESULT_SUCCESS) {
return result;
}
result = cnh_usbhook_invoke_next_reset_advance(irp);
if (result != CNH_RESULT_SUCCESS) {
return result;
}
memcpy(&in_buffer[PIUIO_DRV_BUFFER_SIZE * i], irp->ctrl_buffer.bytes, PIUIO_DRV_BUFFER_SIZE);
}
irp->ctrl_req_type = PATCH_PIUIO_KHACK_CTRL_REQ_TYPE;
irp->ctrl_req = PATCH_PIUIO_KHACK_CTRL_REQ;
irp->ctrl_timeout = PATCH_PIUIO_KHACK_TIMEOUT;
irp->ctrl_buffer.pos = PATCH_PIUIO_KHACK_BUFFER_SIZE;
irp->ctrl_buffer.nbytes = PATCH_PIUIO_KHACK_BUFFER_SIZE;
memcpy(irp->ctrl_buffer.bytes, in_buffer, PATCH_PIUIO_KHACK_BUFFER_SIZE);
}
break;
memcpy(
&in_buffer[PIUIO_DRV_BUFFER_SIZE * i],
irp->ctrl_buffer.bytes,
PIUIO_DRV_BUFFER_SIZE);
}
case CNH_USBHOOK_IRP_OP_CLOSE:
{
_patch_piuio_khack_usb_handle = NULL;
irp->ctrl_req_type = PATCH_PIUIO_KHACK_CTRL_REQ_TYPE;
irp->ctrl_req = PATCH_PIUIO_KHACK_CTRL_REQ;
irp->ctrl_timeout = PATCH_PIUIO_KHACK_TIMEOUT;
irp->ctrl_buffer.pos = PATCH_PIUIO_KHACK_BUFFER_SIZE;
irp->ctrl_buffer.nbytes = PATCH_PIUIO_KHACK_BUFFER_SIZE;
result = cnh_usbhook_invoke_next(irp);
memcpy(
irp->ctrl_buffer.bytes, in_buffer, PATCH_PIUIO_KHACK_BUFFER_SIZE);
}
break;
}
default:
result = cnh_usbhook_invoke_next(irp);
break;
break;
}
return result;
case CNH_USBHOOK_IRP_OP_CLOSE: {
_patch_piuio_khack_usb_handle = NULL;
result = cnh_usbhook_invoke_next(irp);
break;
}
default:
result = cnh_usbhook_invoke_next(irp);
break;
}
return result;
}
+281 -260
View File
@@ -21,13 +21,19 @@
static bool _patch_piuio_enumerate(bool real_exists);
static enum cnh_result _patch_piuio_open(void);
static enum cnh_result _patch_piuio_reset(void);
static enum cnh_result _patch_piuio_control_msg(int request_type, int request, int value, int index,
struct cnh_iobuf* buffer, int timeout);
static enum cnh_result _patch_piuio_control_msg(
int request_type,
int request,
int value,
int index,
struct cnh_iobuf *buffer,
int timeout);
static void _patch_piuio_close(void);
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf* buffer);
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf* buffer);
static enum ptapi_io_piuio_sensor_group _patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf* buffer);
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf *buffer);
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf *buffer);
static enum ptapi_io_piuio_sensor_group
_patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf *buffer);
static const struct cnh_usb_emu_virtdev_ep _patch_piuio_virtdev = {
.pid = PIUIO_DRV_PID,
@@ -42,332 +48,347 @@ static const struct cnh_usb_emu_virtdev_ep _patch_piuio_virtdev = {
static struct ptapi_io_piuio_api _patch_piuio_api;
static enum ptapi_io_piuio_sensor_group _patch_piuio_sensor_group;
void patch_piuio_init(const char* piuio_lib_path)
void patch_piuio_init(const char *piuio_lib_path)
{
if (!piuio_lib_path) {
log_die("No piuio emulation library path specified");
}
if (!piuio_lib_path) {
log_die("No piuio emulation library path specified");
}
/* Load piuio library funcs */
log_info("Loading piuio api implementation %s", piuio_lib_path);
/* Load piuio library funcs */
log_info("Loading piuio api implementation %s", piuio_lib_path);
if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &_patch_piuio_api)) {
log_error("Loading PIUIO API from %s failed", piuio_lib_path);
return;
}
if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &_patch_piuio_api)) {
log_error("Loading PIUIO API from %s failed", piuio_lib_path);
return;
}
cnh_usb_emu_add_virtdevep(&_patch_piuio_virtdev);
cnh_usb_emu_add_virtdevep(&_patch_piuio_virtdev);
log_info("Initialized");
log_info("Initialized");
}
void patch_piuio_shutdown(void)
{
}
static bool _patch_piuio_enumerate(bool real_exists)
{
if (real_exists) {
log_info("Real PIUIO exists but emulation enabled, blocking real");
} else {
log_info("Enumerating PIUIO emulation");
}
if (real_exists) {
log_info("Real PIUIO exists but emulation enabled, blocking real");
} else {
log_info("Enumerating PIUIO emulation");
}
return true;
return true;
}
static enum cnh_result _patch_piuio_open(void)
{
log_info("Opening PIUIO: %s", _patch_piuio_api.ident());
log_info("Opening PIUIO: %s", _patch_piuio_api.ident());
if (!_patch_piuio_api.open()) {
log_error("Opening api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piuio_api.open()) {
log_error("Opening api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
return CNH_RESULT_SUCCESS;
return CNH_RESULT_SUCCESS;
}
static enum cnh_result _patch_piuio_reset(void)
{
log_info("Resetting PIUIO: %s", _patch_piuio_api.ident());
log_info("Resetting PIUIO: %s", _patch_piuio_api.ident());
_patch_piuio_api.close();
_patch_piuio_api.close();
if (!_patch_piuio_api.open()) {
log_error("Resetting api piuio %s failed", _patch_piuio_api.ident());
if (!_patch_piuio_api.open()) {
log_error("Resetting api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
return CNH_RESULT_SUCCESS;
}
static enum cnh_result _patch_piuio_control_msg(
int request_type,
int request,
int value,
int index,
struct cnh_iobuf *buffer,
int timeout)
{
/**
* Expected call pattern for a full game state update on a single frame (when
* done synchronously)
*
* CTRL_OUT: light data + sensor 0
* CTRL_IN: input data of sensor 0
* CTRL_OUT: light data + sensor 1
* CTRL_IN: input data of sensor 1
* CTRL_OUT: light data + sensor 2
* CTRL_IN: input data of sensor 2
* CTRL_OUT: light data + sensor 3
* CTRL_IN: input data of sensor 3
*
* Reduce call overhead to pumptools's piuio API for recv and send polling any
* potential implementation
*/
if (request_type == PIUIO_DRV_USB_CTRL_TYPE_IN &&
request == PIUIO_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Read");
#endif
// Only read buffered inputs, no need to trigger another update since
// this is taken of by the cycle start
_patch_piuio_read_inputs_to_buffer(buffer);
return CNH_RESULT_SUCCESS;
} else if (
request_type == PIUIO_DRV_USB_CTRL_TYPE_OUT &&
request == PIUIO_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
_patch_piuio_read_outputs_from_buffer(buffer);
// Sync properly with sensor cycling by application
// Note: Naturally, the update code below will break if sensors are not
// cycled as expected
_patch_piuio_sensor_group =
_patch_piuio_get_sensor_group_from_buffer(buffer);
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Write: %d", _patch_piuio_sensor_group);
#endif
// Trigger exactly ONE full update cycle on the API implementation on
// every first call of the whole update cycle
if (_patch_piuio_sensor_group == 0) {
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Update API");
#endif
if (!_patch_piuio_api.send()) {
log_error(
"Sending outputs on api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piuio_api.recv()) {
log_error(
"Receiving inputs on api piuio %s failed",
_patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
}
return CNH_RESULT_SUCCESS;
}
} else if (request_type == 0 && request == 0) {
// ITG 2/PIU Pro kernel hack, can be handled by piuio-khack module
// Safety net for visibility if the module is missing
log_error("Unhandled PIUIO kernel hack request detected, cannot dispatch");
static enum cnh_result _patch_piuio_control_msg(int request_type, int request, int value, int index,
struct cnh_iobuf* buffer, int timeout)
{
/**
* Expected call pattern for a full game state update on a single frame (when done synchronously)
*
* CTRL_OUT: light data + sensor 0
* CTRL_IN: input data of sensor 0
* CTRL_OUT: light data + sensor 1
* CTRL_IN: input data of sensor 1
* CTRL_OUT: light data + sensor 2
* CTRL_IN: input data of sensor 2
* CTRL_OUT: light data + sensor 3
* CTRL_IN: input data of sensor 3
*
* Reduce call overhead to pumptools's piuio API for recv and send polling any potential implementation
*/
if (request_type == PIUIO_DRV_USB_CTRL_TYPE_IN && request == PIUIO_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Read");
#endif
// Only read buffered inputs, no need to trigger another update since
// this is taken of by the cycle start
_patch_piuio_read_inputs_to_buffer(buffer);
return CNH_RESULT_SUCCESS;
} else if (request_type == PIUIO_DRV_USB_CTRL_TYPE_OUT && request == PIUIO_DRV_USB_CTRL_REQUEST) {
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes);
return CNH_RESULT_INVALID_PARAMETER;
}
_patch_piuio_read_outputs_from_buffer(buffer);
// Sync properly with sensor cycling by application
// Note: Naturally, the update code below will break if sensors are not cycled
// as expected
_patch_piuio_sensor_group = _patch_piuio_get_sensor_group_from_buffer(buffer);
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Write: %d", _patch_piuio_sensor_group);
#endif
// Trigger exactly ONE full update cycle on the API implementation on
// every first call of the whole update cycle
if (_patch_piuio_sensor_group == 0) {
#ifdef PATCH_PIUIO_CALL_TRACE
log_debug("Update API");
#endif
if (!_patch_piuio_api.send()) {
log_error("Sending outputs on api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
if (!_patch_piuio_api.recv()) {
log_error("Receiving inputs on api piuio %s failed", _patch_piuio_api.ident());
return CNH_RESULT_OTHER_ERROR;
}
}
return CNH_RESULT_SUCCESS;
} else if (request_type == 0 && request == 0) {
// ITG 2/PIU Pro kernel hack, can be handled by piuio-khack module
// Safety net for visibility if the module is missing
log_error("Unhandled PIUIO kernel hack request detected, cannot dispatch");
return CNH_RESULT_INVALID_PARAMETER;
} else {
log_error("Invalid usb control request to PIUIO: 0x%02X", request);
return CNH_RESULT_INVALID_PARAMETER;
}
return CNH_RESULT_INVALID_PARAMETER;
} else {
log_error("Invalid usb control request to PIUIO: 0x%02X", request);
return CNH_RESULT_INVALID_PARAMETER;
}
}
static void _patch_piuio_close(void)
{
log_info("Closing PIUIO: %s", _patch_piuio_api.ident());
log_info("Closing PIUIO: %s", _patch_piuio_api.ident());
_patch_piuio_api.close();
_patch_piuio_api.close();
}
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf* buffer)
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf *buffer)
{
struct ptapi_io_piuio_pad_inputs p1_pad_in;
struct ptapi_io_piuio_pad_inputs p2_pad_in;
struct ptapi_io_piuio_sys_inputs sys_in;
struct ptapi_io_piuio_pad_inputs p1_pad_in;
struct ptapi_io_piuio_pad_inputs p2_pad_in;
struct ptapi_io_piuio_sys_inputs sys_in;
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
_patch_piuio_api.get_input_pad(0, _patch_piuio_sensor_group, &p1_pad_in);
_patch_piuio_api.get_input_pad(1, _patch_piuio_sensor_group, &p2_pad_in);
_patch_piuio_api.get_input_pad(0, _patch_piuio_sensor_group, &p1_pad_in);
_patch_piuio_api.get_input_pad(1, _patch_piuio_sensor_group, &p2_pad_in);
_patch_piuio_api.get_input_sys(&sys_in);
_patch_piuio_api.get_input_sys(&sys_in);
/*
byte 0:
bit 0: sensor p1: LU
bit 1: sensor p1: RU
bit 2: sensor p1: CN
bit 3: sensor p1: LD
bit 4: sensor p1: RD
bit 5:
bit 6:
bit 7:
/*
byte 0:
bit 0: sensor p1: LU
bit 1: sensor p1: RU
bit 2: sensor p1: CN
bit 3: sensor p1: LD
bit 4: sensor p1: RD
bit 5:
bit 6:
bit 7:
byte 1:
bit 0:
bit 1: test
bit 2: coin 1
bit 3:
bit 4:
bit 5:
bit 6: service
bit 7: clear
byte 1:
bit 0:
bit 1: test
bit 2: coin 1
bit 3:
bit 4:
bit 5:
bit 6: service
bit 7: clear
byte 2:
bit 0: sensor p2: LU
bit 1: sensor p2: RU
bit 2: sensor p2: CN
bit 3: sensor p2: LD
bit 4: sensor p2: RD
bit 5:
bit 6:
bit 7:
byte 2:
bit 0: sensor p2: LU
bit 1: sensor p2: RU
bit 2: sensor p2: CN
bit 3: sensor p2: LD
bit 4: sensor p2: RD
bit 5:
bit 6:
bit 7:
byte 3:
bit 0:
bit 1:
bit 2: coin 2
bit 3:
bit 4:
bit 5:
bit 6:
bit 7:
byte 3:
bit 0:
bit 1:
bit 2: coin 2
bit 3:
bit 4:
bit 5:
bit 6:
bit 7:
bytes 4 - 7 dummy
*/
bytes 4 - 7 dummy
*/
/* Player 1 */
buffer->bytes[0] = 0;
/* Player 1 */
buffer->bytes[0] = 0;
buffer->bytes[0] |= ((p1_pad_in.lu ? 1 : 0) << 0);
buffer->bytes[0] |= ((p1_pad_in.ru ? 1 : 0) << 1);
buffer->bytes[0] |= ((p1_pad_in.cn ? 1 : 0) << 2);
buffer->bytes[0] |= ((p1_pad_in.ld ? 1 : 0) << 3);
buffer->bytes[0] |= ((p1_pad_in.rd ? 1 : 0) << 4);
buffer->bytes[0] |= ((p1_pad_in.lu ? 1 : 0) << 0);
buffer->bytes[0] |= ((p1_pad_in.ru ? 1 : 0) << 1);
buffer->bytes[0] |= ((p1_pad_in.cn ? 1 : 0) << 2);
buffer->bytes[0] |= ((p1_pad_in.ld ? 1 : 0) << 3);
buffer->bytes[0] |= ((p1_pad_in.rd ? 1 : 0) << 4);
buffer->bytes[0] ^= 0xFF;
buffer->bytes[0] ^= 0xFF;
/* Player 2 */
buffer->bytes[2] = 0;
/* Player 2 */
buffer->bytes[2] = 0;
buffer->bytes[2] |= ((p1_pad_in.lu ? 1 : 0) << 0);
buffer->bytes[2] |= ((p1_pad_in.ru ? 1 : 0) << 1);
buffer->bytes[2] |= ((p1_pad_in.cn ? 1 : 0) << 2);
buffer->bytes[2] |= ((p1_pad_in.ld ? 1 : 0) << 3);
buffer->bytes[2] |= ((p1_pad_in.rd ? 1 : 0) << 4);
buffer->bytes[2] |= ((p1_pad_in.lu ? 1 : 0) << 0);
buffer->bytes[2] |= ((p1_pad_in.ru ? 1 : 0) << 1);
buffer->bytes[2] |= ((p1_pad_in.cn ? 1 : 0) << 2);
buffer->bytes[2] |= ((p1_pad_in.ld ? 1 : 0) << 3);
buffer->bytes[2] |= ((p1_pad_in.rd ? 1 : 0) << 4);
buffer->bytes[2] ^= 0xFF;
buffer->bytes[2] ^= 0xFF;
/* Sys */
buffer->bytes[1] = 0;
/* Sys */
buffer->bytes[1] = 0;
buffer->bytes[1] |= ((sys_in.test ? 1 : 0) << 1);
buffer->bytes[1] |= ((sys_in.service ? 1 : 0) << 6);
buffer->bytes[1] |= ((sys_in.clear ? 1 : 0) << 7);
buffer->bytes[1] |= ((sys_in.coin ? 1 : 0) << 2);
buffer->bytes[1] |= ((sys_in.test ? 1 : 0) << 1);
buffer->bytes[1] |= ((sys_in.service ? 1 : 0) << 6);
buffer->bytes[1] |= ((sys_in.clear ? 1 : 0) << 7);
buffer->bytes[1] |= ((sys_in.coin ? 1 : 0) << 2);
buffer->bytes[1] ^= 0xFF;
buffer->bytes[1] ^= 0xFF;
/* Apparently, "touching" byte 3 as a whole causes some random and weird input triggering
which results in the service menu popping up. Don't clear the whole byte, touch coin2 only to avoid this */
if (!sys_in.coin2) {
buffer->bytes[3] |= (1 << 2);
} else {
buffer->bytes[3] &= ~(1 << 2);
}
/* Apparently, "touching" byte 3 as a whole causes some random and weird input
triggering which results in the service menu popping up. Don't clear the
whole byte, touch coin2 only to avoid this */
if (!sys_in.coin2) {
buffer->bytes[3] |= (1 << 2);
} else {
buffer->bytes[3] &= ~(1 << 2);
}
buffer->pos = PIUIO_DRV_BUFFER_SIZE;
buffer->pos = PIUIO_DRV_BUFFER_SIZE;
}
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf* buffer)
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf *buffer)
{
struct ptapi_io_piuio_pad_outputs p1_pad_out;
struct ptapi_io_piuio_pad_outputs p2_pad_out;
struct ptapi_io_piuio_cab_outputs cab_out;
struct ptapi_io_piuio_pad_outputs p1_pad_out;
struct ptapi_io_piuio_pad_outputs p2_pad_out;
struct ptapi_io_piuio_cab_outputs cab_out;
/*
byte 0:
bit 0: sensor id bit 0 select sensor to be read for next input request:
bit 1: sensor id bit 1 00 = sens1, 01 = sens2, 10 = sens3, 11 = sens4
bit 2: pad light p1: LU
bit 3: pad light p1: RU
bit 4: pad light p1: CN
bit 5: pad light p1: LD
bit 6: pad light p1: RD
bit 7:
/*
byte 0:
bit 0: sensor id bit 0 select sensor to be read for next input request:
bit 1: sensor id bit 1 00 = sens1, 01 = sens2, 10 = sens3, 11 = sens4
bit 2: pad light p1: LU
bit 3: pad light p1: RU
bit 4: pad light p1: CN
bit 5: pad light p1: LD
bit 6: pad light p1: RD
bit 7:
byte 1:
bit 0:
bit 1:
bit 2: light neons
bit 3: coin counter 2 (front usb ports enable)
bit 4:
bit 5:
bit 6:
bit 7:
byte 1:
bit 0:
bit 1:
bit 2: light neons
bit 3: coin counter 2 (front usb ports enable)
bit 4:
bit 5:
bit 6:
bit 7:
byte 2:
bit 0:
bit 1:
bit 2: pad light p2: LU
bit 3: pad light p2: RU
bit 4: pad light p2: CN
bit 5: pad light p2: LD
bit 6: pad light p2: RD
bit 7: halogen R2
byte 2:
bit 0:
bit 1:
bit 2: pad light p2: LU
bit 3: pad light p2: RU
bit 4: pad light p2: CN
bit 5: pad light p2: LD
bit 6: pad light p2: RD
bit 7: halogen R2
byte 3:
bit 0: halogen R1
bit 1: halogen L2
bit 2: halogen L1
bit 3:
bit 4: coin counter 1
bit 5:
bit 6:
bit 7:
byte 3:
bit 0: halogen R1
bit 1: halogen L2
bit 2: halogen L1
bit 3:
bit 4: coin counter 1
bit 5:
bit 6:
bit 7:
bytes 4 - 7 dummy
*/
bytes 4 - 7 dummy
*/
p1_pad_out.lu = (buffer->bytes[0] & (1 << 2)) > 0;
p1_pad_out.ru = (buffer->bytes[0] & (1 << 3)) > 0;
p1_pad_out.cn = (buffer->bytes[0] & (1 << 4)) > 0;
p1_pad_out.ld = (buffer->bytes[0] & (1 << 5)) > 0;
p1_pad_out.rd = (buffer->bytes[0] & (1 << 6)) > 0;
p1_pad_out.lu = (buffer->bytes[0] & (1 << 2)) > 0;
p1_pad_out.ru = (buffer->bytes[0] & (1 << 3)) > 0;
p1_pad_out.cn = (buffer->bytes[0] & (1 << 4)) > 0;
p1_pad_out.ld = (buffer->bytes[0] & (1 << 5)) > 0;
p1_pad_out.rd = (buffer->bytes[0] & (1 << 6)) > 0;
p2_pad_out.lu = (buffer->bytes[2] & (1 << 2)) > 0;
p2_pad_out.ru = (buffer->bytes[2] & (1 << 3)) > 0;
p2_pad_out.cn = (buffer->bytes[2] & (1 << 4)) > 0;
p2_pad_out.ld = (buffer->bytes[2] & (1 << 5)) > 0;
p2_pad_out.rd = (buffer->bytes[2] & (1 << 6)) > 0;
p2_pad_out.lu = (buffer->bytes[2] & (1 << 2)) > 0;
p2_pad_out.ru = (buffer->bytes[2] & (1 << 3)) > 0;
p2_pad_out.cn = (buffer->bytes[2] & (1 << 4)) > 0;
p2_pad_out.ld = (buffer->bytes[2] & (1 << 5)) > 0;
p2_pad_out.rd = (buffer->bytes[2] & (1 << 6)) > 0;
cab_out.bass = (buffer->bytes[1] & (1 << 2)) > 0;
cab_out.halo_r2 = (buffer->bytes[2] & (1 << 7)) > 0;
cab_out.halo_r1 = (buffer->bytes[3] & (1 << 0)) > 0;
cab_out.halo_l2 = (buffer->bytes[3] & (1 << 1)) > 0;
cab_out.halo_l1 = (buffer->bytes[3] & (1 << 2)) > 0;
cab_out.bass = (buffer->bytes[1] & (1 << 2)) > 0;
cab_out.halo_r2 = (buffer->bytes[2] & (1 << 7)) > 0;
cab_out.halo_r1 = (buffer->bytes[3] & (1 << 0)) > 0;
cab_out.halo_l2 = (buffer->bytes[3] & (1 << 1)) > 0;
cab_out.halo_l1 = (buffer->bytes[3] & (1 << 2)) > 0;
_patch_piuio_api.set_output_pad(0, &p1_pad_out);
_patch_piuio_api.set_output_pad(1, &p2_pad_out);
_patch_piuio_api.set_output_cab(&cab_out);
_patch_piuio_api.set_output_pad(0, &p1_pad_out);
_patch_piuio_api.set_output_pad(1, &p2_pad_out);
_patch_piuio_api.set_output_cab(&cab_out);
}
static enum ptapi_io_piuio_sensor_group _patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf* buffer)
static enum ptapi_io_piuio_sensor_group
_patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf *buffer)
{
return (enum ptapi_io_piuio_sensor_group) (buffer->bytes[0] & 0x03);
return (enum ptapi_io_piuio_sensor_group)(buffer->bytes[0] & 0x03);
}
+1 -1
View File
@@ -12,7 +12,7 @@
*
* @param piuio_lib_path Path to a library implementing the piuio API
*/
void patch_piuio_init(const char* piuio_lib_path);
void patch_piuio_init(const char *piuio_lib_path);
/**
* Shut down the patch module
+9 -8
View File
@@ -10,16 +10,17 @@ static enum cnh_result _patch_ram_wipe_filehook(struct cnh_filehook_irp *irp);
void patch_ram_wipe_init(void)
{
cnh_filehook_push_handler(_patch_ram_wipe_filehook);
log_info("Initialized");
cnh_filehook_push_handler(_patch_ram_wipe_filehook);
log_info("Initialized");
}
static enum cnh_result _patch_ram_wipe_filehook(struct cnh_filehook_irp *irp)
{
if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN && !strcmp(irp->open_filename, "/dev/ram0")) {
log_info("Killing ram wipe");
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
} else {
return cnh_filehook_invoke_next(irp);
}
if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN &&
!strcmp(irp->open_filename, "/dev/ram0")) {
log_info("Killing ram wipe");
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
} else {
return cnh_filehook_invoke_next(irp);
}
}
+4 -4
View File
@@ -6,9 +6,9 @@
void patch_redir_init()
{
cnh_fshook_push_handler(cnh_redir_fshook);
cnh_filehook_push_handler(cnh_redir_filehook);
cnh_iohook_push_handler(cnh_redir_iohook);
cnh_fshook_push_handler(cnh_redir_fshook);
cnh_filehook_push_handler(cnh_redir_filehook);
cnh_iohook_push_handler(cnh_redir_iohook);
log_info("Initialized");
log_info("Initialized");
}
+1 -1
View File
@@ -9,4 +9,4 @@
*/
void patch_redir_init();
#endif //PATCH_REDIR_H
#endif // PATCH_REDIR_H
+24 -24
View File
@@ -15,39 +15,39 @@ static bool patch_sigsevc_halt_on_segv;
static void patch_sigsegv_handler(int signal, __sighandler_t orig_handler)
{
log_error("===================");
log_error("!!!!! SIGSEGV !!!!!");
log_error("===================");
log_error("!!!!! SIGSEGV !!!!!");
void* array[128];
size_t size;
char** strings;
void *array[128];
size_t size;
char **strings;
size = (size_t) backtrace(array, sizeof(array));
strings = backtrace_symbols(array, size);
size = (size_t) backtrace(array, sizeof(array));
strings = backtrace_symbols(array, size);
log_error("Backtrace (%d frames):", size);
log_error("Backtrace (%d frames):", size);
for (int i = 0; i < size; i++) {
log_error("%s", strings[i]);
for (int i = 0; i < size; i++) {
log_error("%s", strings[i]);
}
free(strings);
if (patch_sigsevc_halt_on_segv) {
log_error("Halting for debugger...");
while (true) {
sleep(1);
}
}
free(strings);
if (patch_sigsevc_halt_on_segv) {
log_error("Halting for debugger...");
while (true) {
sleep(1);
}
}
exit(-1);
exit(-1);
}
void patch_sigsegv_init(bool halt_on_segv)
{
patch_sigsevc_halt_on_segv = halt_on_segv;
patch_sigsevc_halt_on_segv = halt_on_segv;
cnh_sig_install(SIGSEGV, patch_sigsegv_handler);
log_info("Initialized");
cnh_sig_install(SIGSEGV, patch_sigsegv_handler);
log_info("Initialized");
}
+40 -37
View File
@@ -1,66 +1,69 @@
#define LOG_MODULE "patch-sound"
#include <alsa/asoundlib.h>
#include <grp.h>
#include <sys/types.h>
#include <grp.h>
#include "capnhook/hook/lib.h"
#include "util/log.h"
typedef int (*snd_pcm_open_t)(snd_pcm_t** pcmp, const char* name,
snd_pcm_stream_t stream, int mode);
typedef int (*snd_pcm_open_t)(
snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode);
static snd_pcm_open_t patch_sound_real_snd_pcm_open;
static const char* patch_sound_dev_name;
static const char *patch_sound_dev_name;
int snd_pcm_open(snd_pcm_t** pcmp, const char* name, snd_pcm_stream_t stream, int mode)
int snd_pcm_open(
snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
{
int ret = 0;
int retry_count = 5;
int ret = 0;
int retry_count = 5;
log_debug("snd_pcm_open: %s, stream %d, mode %d", name, stream, mode);
log_debug("snd_pcm_open: %s, stream %d, mode %d", name, stream, mode);
if (!patch_sound_real_snd_pcm_open) {
patch_sound_real_snd_pcm_open = (snd_pcm_open_t) cnh_lib_get_func_addr("snd_pcm_open");
}
if (!patch_sound_real_snd_pcm_open) {
patch_sound_real_snd_pcm_open =
(snd_pcm_open_t) cnh_lib_get_func_addr("snd_pcm_open");
}
if (patch_sound_dev_name) {
log_info("Opening sound device %s instead of %s", patch_sound_dev_name, name);
if (patch_sound_dev_name) {
log_info(
"Opening sound device %s instead of %s", patch_sound_dev_name, name);
name = patch_sound_dev_name;
}
name = patch_sound_dev_name;
}
/*
Notes about exceed and how it fucked up using alsa:
- Opening the same (hw:0) device multiple times without closing
- Opening and closing the device on each effect play
- No proper error handling on snd_pcm_open return
*/
/*
Notes about exceed and how it fucked up using alsa:
- Opening the same (hw:0) device multiple times without closing
- Opening and closing the device on each effect play
- No proper error handling on snd_pcm_open return
*/
/* Using dmix instead of hw:0 on exceed, snd_pcm_open sometimes returns
with a bad fd but after another retry, everything's fine */
while (retry_count > 0) {
ret = patch_sound_real_snd_pcm_open(pcmp, name, stream, mode);
if (ret < 0) {
retry_count--;
} else {
break;
}
}
/* Using dmix instead of hw:0 on exceed, snd_pcm_open sometimes returns
with a bad fd but after another retry, everything's fine */
while (retry_count > 0) {
ret = patch_sound_real_snd_pcm_open(pcmp, name, stream, mode);
if (ret < 0) {
log_error("snd_pcm_open failed: %s", snd_strerror(ret));
retry_count--;
} else {
break;
}
}
return ret;
if (ret < 0) {
log_error("snd_pcm_open failed: %s", snd_strerror(ret));
}
return ret;
}
void patch_sound_init(const char* dev_name)
void patch_sound_init(const char *dev_name)
{
patch_sound_dev_name = dev_name;
patch_sound_dev_name = dev_name;
log_info("Initialized");
log_info("Initialized");
}
+1 -1
View File
@@ -10,6 +10,6 @@
*
* @param dev_name Sound device name to open instead of whatever pump decides
*/
void patch_sound_init(const char* dev_name);
void patch_sound_init(const char *dev_name);
#endif
+2 -2
View File
@@ -6,7 +6,7 @@
void patch_usb_emu_init()
{
cnh_usbhook_push_handler(&cnh_usb_emu);
cnh_usbhook_push_handler(&cnh_usb_emu);
log_info("Initialized");
log_info("Initialized");
}
+2 -2
View File
@@ -6,7 +6,7 @@
void patch_usb_init_fix_init()
{
cnh_usbhook_push_handler(&cnh_usb_init_fix);
cnh_usbhook_push_handler(&cnh_usb_init_fix);
log_info("Initialized");
log_info("Initialized");
}
+16 -13
View File
@@ -5,25 +5,28 @@
#include "usb-mnt.h"
static const char* patch_usb_mnt_player[2] = {"/mnt/0", "/mnt/1"};
static const char *patch_usb_mnt_player[2] = {"/mnt/0", "/mnt/1"};
// Invalid files are used to detect if mounting the usb stick was successful
static const char* patch_usb_mnt_player_invalid[2] = {"/mnt/0/invalid", "/mnt/1/invalid"};
static const char *patch_usb_mnt_player_invalid[2] = {
"/mnt/0/invalid", "/mnt/1/invalid"};
void patch_usb_mnt_init(void)
{
for (uint8_t i = 0; i < 2; i++) {
if (!util_fs_path_exists(patch_usb_mnt_player[i])) {
log_info("%s does not exist, creating", patch_usb_mnt_player[i]);
for (uint8_t i = 0; i < 2; i++) {
if (!util_fs_path_exists(patch_usb_mnt_player[i])) {
log_info("%s does not exist, creating", patch_usb_mnt_player[i]);
if (!util_fs_mkdir(patch_usb_mnt_player[i])) {
log_error("Creating directory %s failed", patch_usb_mnt_player[i]);
}
if (!util_fs_mkdir(patch_usb_mnt_player[i])) {
log_error("Creating directory %s failed", patch_usb_mnt_player[i]);
}
if (!util_fs_mkfile(patch_usb_mnt_player_invalid[i])) {
log_error("Creating invalid indicator file %s failed", patch_usb_mnt_player_invalid[i]);
}
}
if (!util_fs_mkfile(patch_usb_mnt_player_invalid[i])) {
log_error(
"Creating invalid indicator file %s failed",
patch_usb_mnt_player_invalid[i]);
}
}
}
log_info("Initialized");
log_info("Initialized");
}
+39 -33
View File
@@ -20,54 +20,60 @@ static strcasecmp_t patch_usb_unlock_real_strcasecmp;
int sscanf(const char *str, const char *format, ...)
{
if (!patch_usb_unlock_real_sscanf) {
patch_usb_unlock_real_sscanf = (sscanf_t) cnh_lib_get_func_addr("sscanf");
}
if (!patch_usb_unlock_real_sscanf) {
patch_usb_unlock_real_sscanf = (sscanf_t) cnh_lib_get_func_addr("sscanf");
}
va_list ap;
va_start(ap, format);
va_list ap;
va_start(ap, format);
if (!strcmp(format, "P: Vendor=%4x ProdID=%4x")) {
log_debug("Spoofing VID 0x058f for usb stick");
if (!strcmp(format, "P: Vendor=%4x ProdID=%4x")) {
log_debug("Spoofing VID 0x058f for usb stick");
/* unpack argument list, we know we got 2 arguments here */
/* VID */
*va_arg(ap, int*) = 0x058f;
/* PID */
*va_arg(ap, int*) = 0;
/* unpack argument list, we know we got 2 arguments here */
/* VID */
*va_arg(ap, int *) = 0x058f;
/* PID */
*va_arg(ap, int *) = 0;
va_end(ap);
return 2;
}
va_end(ap);
return 2;
}
if (!strcmp(format, "S: SerialNumber=%s")) {
log_debug("Spoofing serial number of usb stick to kill serial number locking of profile in a moment...");
memcpy(va_arg(ap, char*), SERIAL_UNLOCK_TOKEN, strlen(SERIAL_UNLOCK_TOKEN) + 1);
if (!strcmp(format, "S: SerialNumber=%s")) {
log_debug(
"Spoofing serial number of usb stick to kill serial number locking of "
"profile in a moment...");
memcpy(
va_arg(ap, char *),
SERIAL_UNLOCK_TOKEN,
strlen(SERIAL_UNLOCK_TOKEN) + 1);
va_end(ap);
return 1;
}
va_end(ap);
return 1;
}
int ret = vsscanf(str, format, ap);
va_end(ap);
return ret;
int ret = vsscanf(str, format, ap);
va_end(ap);
return ret;
}
int strcasecmp(const char *s1, const char *s2)
{
if (!patch_usb_unlock_real_strcasecmp) {
patch_usb_unlock_real_strcasecmp = (strcasecmp_t) cnh_lib_get_func_addr("strcasecmp");
}
if (!patch_usb_unlock_real_strcasecmp) {
patch_usb_unlock_real_strcasecmp =
(strcasecmp_t) cnh_lib_get_func_addr("strcasecmp");
}
if (!strcmp(s2, SERIAL_UNLOCK_TOKEN)) {
log_debug("Caught serial unlock token...unlocking profile");
return 0;
}
if (!strcmp(s2, SERIAL_UNLOCK_TOKEN)) {
log_debug("Caught serial unlock token...unlocking profile");
return 0;
}
return patch_usb_unlock_real_strcasecmp(s1, s2);
return patch_usb_unlock_real_strcasecmp(s1, s2);
}
void patch_usb_unlock_init(void)
{
log_info("Initialized");
log_info("Initialized");
}
+120 -95
View File
@@ -1,8 +1,8 @@
#define LOG_MODULE "patch-usbfs"
#include <glob.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "capnhook/hook/lib.h"
@@ -10,121 +10,146 @@
#include "util/fs.h"
#include "util/log.h"
typedef int (*vsprintf_t)(char* str, const char* format, va_list ap);
typedef int (*vsprintf_t)(char *str, const char *format, va_list ap);
typedef int (*sprintf_t)(char *str, const char *format, ...);
static vsprintf_t patch_usbfs_vsprintf_orig;
static sprintf_t patch_usbfs_sprintf_orig;
static const char* patch_usbfs_usb_str = "/sys/bus/usb/devices/";
static const char *patch_usbfs_usb_str = "/sys/bus/usb/devices/";
int sprintf(char *str, const char *format, ...)
{
va_list ap;
va_start(ap, format);
int ret = vsprintf(str, format, ap);
va_end(ap);
return ret;
va_list ap;
va_start(ap, format);
int ret = vsprintf(str, format, ap);
va_end(ap);
return ret;
}
int __sprintf_chk(char *dest, int flags, size_t dest_len_from_compiler, const char *format, ...)
int __sprintf_chk(
char *dest,
int flags,
size_t dest_len_from_compiler,
const char *format,
...)
{
int ret;
va_list ap;
va_start(ap, format);
int ret;
va_list ap;
va_start(ap, format);
/* fuck...why did you guys have to switch from sprintf to sprintf_chk?
everything was perfectly fine... and you give a shit about "safe" code,
which doesn't make this mess better... */
ret = vsprintf(dest, format, ap);
/* fuck...why did you guys have to switch from sprintf to sprintf_chk?
everything was perfectly fine... and you give a shit about "safe" code,
which doesn't make this mess better... */
ret = vsprintf(dest, format, ap);
va_end(ap);
return ret;
va_end(ap);
return ret;
}
int vsprintf(char* str, const char* format, va_list ap)
int vsprintf(char *str, const char *format, va_list ap)
{
if (!patch_usbfs_vsprintf_orig) {
patch_usbfs_vsprintf_orig = (vsprintf_t) cnh_lib_get_func_addr("vsprintf");
if (!patch_usbfs_vsprintf_orig) {
patch_usbfs_vsprintf_orig = (vsprintf_t) cnh_lib_get_func_addr("vsprintf");
}
if (!patch_usbfs_sprintf_orig) {
patch_usbfs_sprintf_orig = (sprintf_t) cnh_lib_get_func_addr("sprintf");
}
/* This path does not work on newer kernels (not sure which version it
started but everything > 3.18 doesn't work) */
// nx2/nxa path:
// /sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block:sd*
// fiesta and newer:
// /sys/bus/usb/devices/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block/sd*
if (!strncmp(patch_usbfs_usb_str, format, strlen(patch_usbfs_usb_str))) {
/* unpack argument list, we know we got 4 arguments here
the second pair is a dupe of the first one */
uint8_t bus = (uint8_t) va_arg(ap, int);
uint8_t port = (uint8_t) va_arg(ap, int);
// Removed because it spams the log. Put it back when debugging usb profile
// mounting related issues log_debug("Patching lookup of '%s' device node
// for bus %d, port %d.", format, bus, port);
/* note: ports start with 1 (not 0) in sysfs */
/* because the linux kernel likes to change things here often, we have to
consider different paths. for each path we encountered so far (add more
if missing from different kernel versions) just
check if the path exists and use it */
int counter = 0;
while (counter <= 2) {
switch (counter) {
case 0:
patch_usbfs_sprintf_orig(
str,
"/sys/bus/usb/devices/%d-1.%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*",
bus,
port);
break;
case 1:
patch_usbfs_sprintf_orig(
str,
"/sys/bus/usb/devices/%d-%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*",
bus,
port);
break;
case 2:
// Discovered that the string needs to be changed on 5.5.6. Probably
// changed slightly before that version
patch_usbfs_sprintf_orig(
str,
"/sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*",
bus,
port,
bus,
port);
break;
default:
log_error(
"Could not find path in sys-fs to lookup usb drive block device. "
"Likely, you have a "
"kernel version that uses a (slightly) different path. This "
"(new) path must be added in "
"order to get usb drives showing up in the game.");
break;
}
glob_t gl;
// Pump does the same after returning from this hooked call. Because there
// are different file system layouts depending on the kernel version, try
// the above list using the same method with glob
if (!glob(str, 4, NULL, &gl)) {
globfree(&gl);
break;
}
globfree(&gl);
counter++;
}
if (!patch_usbfs_sprintf_orig) {
patch_usbfs_sprintf_orig = (sprintf_t) cnh_lib_get_func_addr("sprintf");
}
/* original argument count */
return 4;
}
/* This path does not work on newer kernels (not sure which version it
started but everything > 3.18 doesn't work) */
// nx2/nxa path:
// /sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block:sd*
// fiesta and newer:
// /sys/bus/usb/devices/%d-%d:1.0/host*/target*:0:0/*:0:0:0/block/sd*
if (!strncmp(patch_usbfs_usb_str, format, strlen(patch_usbfs_usb_str))) {
/* unpack argument list, we know we got 4 arguments here
the second pair is a dupe of the first one */
uint8_t bus = (uint8_t) va_arg(ap, int);
uint8_t port = (uint8_t) va_arg(ap, int);
// Removed because it spams the log. Put it back when debugging usb profile mounting related issues
// log_debug("Patching lookup of '%s' device node for bus %d, port %d.", format, bus, port);
/* note: ports start with 1 (not 0) in sysfs */
/* because the linux kernel likes to change things here often, we have to consider different paths.
for each path we encountered so far (add more if missing from different kernel versions) just
check if the path exists and use it */
int counter = 0;
while (counter <= 2) {
switch (counter) {
case 0:
patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-1.%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*", bus, port);
break;
case 1:
patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*", bus, port);
break;
case 2:
// Discovered that the string needs to be changed on 5.5.6. Probably changed slightly before that
// version
patch_usbfs_sprintf_orig(str, "/sys/bus/usb/devices/%d-%d/%d-%d:1.0/host*/"
"target*:0:0/*:0:0:0/block/sd*", bus, port, bus, port);
break;
default:
log_error("Could not find path in sys-fs to lookup usb drive block device. Likely, you have a "
"kernel version that uses a (slightly) different path. This (new) path must be added in "
"order to get usb drives showing up in the game.");
break;
}
glob_t gl;
// Pump does the same after returning from this hooked call. Because there are different file system
// layouts depending on the kernel version, try the above list using the same method with glob
if (!glob(str, 4, NULL, &gl)) {
globfree(&gl);
break;
}
globfree(&gl);
counter++;
}
/* original argument count */
return 4;
}
return patch_usbfs_vsprintf_orig(str, format, ap);
return patch_usbfs_vsprintf_orig(str, format, ap);
}
void patch_usbfs_init()
{
log_info("Initialized");
log_info("Initialized");
}
+237 -176
View File
@@ -1,9 +1,9 @@
#define LOG_MODULE "patch-x11-event-loop"
#include <X11/Xutil.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <X11/Xutil.h>
#include "capnhook/hook/lib.h"
@@ -14,16 +14,26 @@
#include "util/time.h"
struct patch_x11_event_loop_ctx {
Display* display;
Window window;
pthread_t thread;
atomic_int run;
Display *display;
Window window;
pthread_t thread;
atomic_int run;
};
typedef Window (*XCreateWindow_t)(Display *display, Window parent, int x, int y, unsigned int width,
unsigned int height, unsigned int border_width, int depth, unsigned int _class, Visual *visual,
unsigned long valuemask, XSetWindowAttributes *attributes);
typedef Display* (*XOpenDisplay_t)(const char *display_name);
typedef Window (*XCreateWindow_t)(
Display *display,
Window parent,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int border_width,
int depth,
unsigned int _class,
Visual *visual,
unsigned long valuemask,
XSetWindowAttributes *attributes);
typedef Display *(*XOpenDisplay_t)(const char *display_name);
typedef int (*XDestroyWindow_t)(Display *display, Window w);
static XCreateWindow_t patch_x11_event_loop_real_XCreateWindow;
@@ -31,239 +41,290 @@ static XOpenDisplay_t patch_x11_event_loop_real_XOpenDisplay;
static XDestroyWindow_t patch_x11_event_loop_real_XDestroyWindow;
static bool patch_x11_event_loop_enabled;
static struct patch_x11_event_loop_ctx* patch_x11_event_loop_ctx;
static struct patch_x11_event_loop_ctx *patch_x11_event_loop_ctx;
static pthread_mutex_t patch_x11_event_loop_input_handlers_lock;
static const struct ptapi_io_x11_input_hook_handler** patch_x11_event_loop_input_handlers;
static const struct ptapi_io_x11_input_hook_handler *
*patch_x11_event_loop_input_handlers;
static size_t patch_x11_event_loop_num_input_handlers;
static bool patch_x11_event_loop_is_key_repeated(Display* display, XEvent* event)
static bool
patch_x11_event_loop_is_key_repeated(Display *display, XEvent *event)
{
/* When a key is repeated, there will be two events: released, followed by another immediate pressed.
So check to see if another pressed is present */
if (!XPending(display)) {
return false;
}
XEvent e;
XPeekEvent(display, &e);
if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode && (e.xkey.time - event->xkey.time) < 2) {
XNextEvent(display, &e);
return true;
}
/* When a key is repeated, there will be two events: released, followed by
another immediate pressed. So check to see if another pressed is present */
if (!XPending(display)) {
return false;
}
XEvent e;
XPeekEvent(display, &e);
if (e.type == KeyPress && e.xkey.keycode == event->xkey.keycode &&
(e.xkey.time - event->xkey.time) < 2) {
XNextEvent(display, &e);
return true;
}
return false;
}
static void* patch_x11_event_loop_run(void* args)
static void *patch_x11_event_loop_run(void *args)
{
log_info("Running X11 event loop thread");
log_info("Running X11 event loop thread");
struct patch_x11_event_loop_ctx* ctx = (struct patch_x11_event_loop_ctx*) args;
struct patch_x11_event_loop_ctx *ctx =
(struct patch_x11_event_loop_ctx *) args;
if (XSelectInput(ctx->display, ctx->window, KeyPressMask | KeyReleaseMask) == BadWindow) {
log_error("XSelectInput failed");
return NULL;
}
if (XSelectInput(ctx->display, ctx->window, KeyPressMask | KeyReleaseMask) ==
BadWindow) {
log_error("XSelectInput failed");
return NULL;
}
XGrabKeyboard(ctx->display, ctx->window, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabKeyboard(
ctx->display, ctx->window, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
while (atomic_load(&ctx->run) > 0) {
while (atomic_load(&ctx->run) > 0 && XPending(ctx->display) > 0) {
XEvent event;
KeySym key;
while (atomic_load(&ctx->run) > 0) {
while (atomic_load(&ctx->run) > 0 && XPending(ctx->display) > 0) {
XEvent event;
KeySym key;
if (XNextEvent(ctx->display, &event) != Success) {
log_error("XNextEvent");
continue;
if (XNextEvent(ctx->display, &event) != Success) {
log_error("XNextEvent");
continue;
}
switch (event.type) {
case KeyPress: {
/* Mask out the modifier states X11 sets and read again */
event.xkey.state &= ~ShiftMask;
event.xkey.state &= ~LockMask;
XLookupString(&event.xkey, 0, 0, &key, 0);
/* Dispatch to external input handlers */
if (patch_x11_event_loop_num_input_handlers > 0) {
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers;
i++) {
if (patch_x11_event_loop_input_handlers[i]->dispatch_key_press) {
patch_x11_event_loop_input_handlers[i]->dispatch_key_press(key);
}
}
switch (event.type) {
case KeyPress:
{
/* Mask out the modifier states X11 sets and read again */
event.xkey.state &= ~ShiftMask;
event.xkey.state &= ~LockMask;
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
}
XLookupString(&event.xkey, 0, 0, &key, 0);
/* Dispatch to external input handlers */
if (patch_x11_event_loop_num_input_handlers > 0) {
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers; i++) {
if (patch_x11_event_loop_input_handlers[i]->dispatch_key_press) {
patch_x11_event_loop_input_handlers[i]->dispatch_key_press(key);
}
}
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
}
break;
}
case KeyRelease:
{
/* Mask out the modifier states X11 sets and read again */
event.xkey.state &= ~ShiftMask;
event.xkey.state &= ~LockMask;
XLookupString(&event.xkey, 0, 0, &key, 0);
/* Dispatch to external input handlers */
if (patch_x11_event_loop_num_input_handlers > 0) {
/* Dispatch release if key is not repeated */
if (!patch_x11_event_loop_is_key_repeated(ctx->display, &event)) {
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers; i++) {
if (patch_x11_event_loop_input_handlers[i]->dispatch_key_release) {
patch_x11_event_loop_input_handlers[i]->dispatch_key_release(key);
}
}
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
}
}
break;
}
default:
break;
}
break;
}
// Avoid CPU banging
util_time_sleep_ms(1);
case KeyRelease: {
/* Mask out the modifier states X11 sets and read again */
event.xkey.state &= ~ShiftMask;
event.xkey.state &= ~LockMask;
XLookupString(&event.xkey, 0, 0, &key, 0);
/* Dispatch to external input handlers */
if (patch_x11_event_loop_num_input_handlers > 0) {
/* Dispatch release if key is not repeated */
if (!patch_x11_event_loop_is_key_repeated(ctx->display, &event)) {
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
for (size_t i = 0; i < patch_x11_event_loop_num_input_handlers;
i++) {
if (patch_x11_event_loop_input_handlers[i]
->dispatch_key_release) {
patch_x11_event_loop_input_handlers[i]->dispatch_key_release(
key);
}
}
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
}
}
break;
}
default:
break;
}
}
log_info("Finished X11 event loop thread");
// Avoid CPU banging
util_time_sleep_ms(1);
}
return NULL;
log_info("Finished X11 event loop thread");
return NULL;
}
Display *XOpenDisplay(const char *display_name)
{
if (!patch_x11_event_loop_real_XOpenDisplay) {
patch_x11_event_loop_real_XOpenDisplay = (XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay");
}
if (!patch_x11_event_loop_real_XOpenDisplay) {
patch_x11_event_loop_real_XOpenDisplay =
(XOpenDisplay_t) cnh_lib_get_func_addr("XOpenDisplay");
}
log_debug("XOpenDisplay: %s", display_name);
log_debug("XOpenDisplay: %s", display_name);
// This function needs to be called before any other X11 function is called.
// Required to pump events in separate thread
if (patch_x11_event_loop_enabled && XInitThreads() != Success) {
log_error("XInitThreads failed");
}
// This function needs to be called before any other X11 function is called.
// Required to pump events in separate thread
if (patch_x11_event_loop_enabled && XInitThreads() != Success) {
log_error("XInitThreads failed");
}
Display* res = patch_x11_event_loop_real_XOpenDisplay(display_name);
Display *res = patch_x11_event_loop_real_XOpenDisplay(display_name);
if (!res) {
log_error("XOpenDisplay returned NULL. This might indicate that your environment is not properly setup. Check "
" that you have GPU drivers installed and configured properly and that OpenGL hardware acceleration is "
" working (use the command line tool \"glxinfo\").");
}
if (!res) {
log_error(
"XOpenDisplay returned NULL. This might indicate that your environment "
"is not properly setup. Check "
" that you have GPU drivers installed and configured properly and that "
"OpenGL hardware acceleration is "
" working (use the command line tool \"glxinfo\").");
}
return res;
return res;
}
Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height,
unsigned int border_width, int depth, unsigned int _class, Visual *visual, unsigned long valuemask,
XSetWindowAttributes *attributes)
Window XCreateWindow(
Display *display,
Window parent,
int x,
int y,
unsigned int width,
unsigned int height,
unsigned int border_width,
int depth,
unsigned int _class,
Visual *visual,
unsigned long valuemask,
XSetWindowAttributes *attributes)
{
log_debug("XCreateWindow");
log_debug("XCreateWindow");
if (!patch_x11_event_loop_real_XCreateWindow) {
patch_x11_event_loop_real_XCreateWindow = (XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow");
}
if (!patch_x11_event_loop_real_XCreateWindow) {
patch_x11_event_loop_real_XCreateWindow =
(XCreateWindow_t) cnh_lib_get_func_addr("XCreateWindow");
}
Window w = patch_x11_event_loop_real_XCreateWindow(display, parent, x, y, width, height, border_width, depth,
_class, visual, valuemask, attributes);
Window w = patch_x11_event_loop_real_XCreateWindow(
display,
parent,
x,
y,
width,
height,
border_width,
depth,
_class,
visual,
valuemask,
attributes);
if (patch_x11_event_loop_enabled && !patch_x11_event_loop_ctx) {
patch_x11_event_loop_ctx = util_xmalloc(sizeof(struct patch_x11_event_loop_ctx));
if (patch_x11_event_loop_enabled && !patch_x11_event_loop_ctx) {
patch_x11_event_loop_ctx =
util_xmalloc(sizeof(struct patch_x11_event_loop_ctx));
patch_x11_event_loop_ctx->display = display;
patch_x11_event_loop_ctx->window = w;
patch_x11_event_loop_ctx->run = ATOMIC_VAR_INIT(1);
patch_x11_event_loop_ctx->display = display;
patch_x11_event_loop_ctx->window = w;
patch_x11_event_loop_ctx->run = ATOMIC_VAR_INIT(1);
pthread_create(&patch_x11_event_loop_ctx->thread, NULL, patch_x11_event_loop_run, patch_x11_event_loop_ctx);
}
pthread_create(
&patch_x11_event_loop_ctx->thread,
NULL,
patch_x11_event_loop_run,
patch_x11_event_loop_ctx);
}
return w;
return w;
}
int XDestroyWindow(Display *display, Window w)
{
log_debug("XDestroyWindow");
log_debug("XDestroyWindow");
if (!patch_x11_event_loop_real_XDestroyWindow) {
patch_x11_event_loop_real_XDestroyWindow = (XDestroyWindow_t) cnh_lib_get_func_addr("XDestroyWindow");
}
if (!patch_x11_event_loop_real_XDestroyWindow) {
patch_x11_event_loop_real_XDestroyWindow =
(XDestroyWindow_t) cnh_lib_get_func_addr("XDestroyWindow");
}
if (patch_x11_event_loop_enabled && patch_x11_event_loop_ctx) {
log_debug("Stopping X11 event loop thread...");
if (patch_x11_event_loop_enabled && patch_x11_event_loop_ctx) {
log_debug("Stopping X11 event loop thread...");
atomic_store(&patch_x11_event_loop_ctx->run, 0);
pthread_join(patch_x11_event_loop_ctx->thread, NULL);
free(patch_x11_event_loop_ctx);
patch_x11_event_loop_ctx = NULL;
atomic_store(&patch_x11_event_loop_ctx->run, 0);
pthread_join(patch_x11_event_loop_ctx->thread, NULL);
free(patch_x11_event_loop_ctx);
patch_x11_event_loop_ctx = NULL;
log_debug("Stopped X11 event loop thread");
}
log_debug("Stopped X11 event loop thread");
}
return patch_x11_event_loop_real_XDestroyWindow(display, w);
return patch_x11_event_loop_real_XDestroyWindow(display, w);
}
void patch_x11_event_loop_init()
{
patch_x11_event_loop_enabled = true;
log_info("Initialized");
patch_x11_event_loop_enabled = true;
log_info("Initialized");
}
void patch_x11_event_loop_add_input_handler(const char* lib_with_handler_impl)
void patch_x11_event_loop_add_input_handler(const char *lib_with_handler_impl)
{
const struct ptapi_io_x11_input_hook_handler** new_array;
size_t new_size;
void* lib_handle;
ptapi_io_x11_input_handler_hook_t input_handler_hook_func;
const struct ptapi_io_x11_input_hook_handler* input_handler_hook;
const struct ptapi_io_x11_input_hook_handler **new_array;
size_t new_size;
void *lib_handle;
ptapi_io_x11_input_handler_hook_t input_handler_hook_func;
const struct ptapi_io_x11_input_hook_handler *input_handler_hook;
if (!lib_with_handler_impl) {
log_die("No library path with input handler implementation specified");
}
if (!lib_with_handler_impl) {
log_die("No library path with input handler implementation specified");
}
log_info("Loading library with x11-input-handler api implementation %s", lib_with_handler_impl);
log_info(
"Loading library with x11-input-handler api implementation %s",
lib_with_handler_impl);
lib_handle = cnh_lib_load(lib_with_handler_impl);
lib_handle = cnh_lib_load(lib_with_handler_impl);
input_handler_hook_func = (ptapi_io_x11_input_handler_hook_t)
cnh_lib_get_func_addr_handle(lib_handle, "ptapi_io_x11_input_handler_hook");
input_handler_hook_func =
(ptapi_io_x11_input_handler_hook_t) cnh_lib_get_func_addr_handle(
lib_handle, "ptapi_io_x11_input_handler_hook");
input_handler_hook = input_handler_hook_func();
input_handler_hook = input_handler_hook_func();
if (!input_handler_hook) {
log_warn("Library impl %s returned NULL hook handler, skipping", lib_with_handler_impl);
return;
}
if (!input_handler_hook) {
log_warn(
"Library impl %s returned NULL hook handler, skipping",
lib_with_handler_impl);
return;
}
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
pthread_mutex_lock(&patch_x11_event_loop_input_handlers_lock);
new_size = patch_x11_event_loop_num_input_handlers + 1;
new_array = realloc(patch_x11_event_loop_input_handlers, new_size * sizeof(struct ptapi_io_input_hook_handler*));
new_size = patch_x11_event_loop_num_input_handlers + 1;
new_array = realloc(
patch_x11_event_loop_input_handlers,
new_size * sizeof(struct ptapi_io_input_hook_handler *));
if (new_array != NULL) {
patch_x11_event_loop_input_handlers = new_array;
if (new_array != NULL) {
patch_x11_event_loop_input_handlers = new_array;
patch_x11_event_loop_input_handlers[patch_x11_event_loop_num_input_handlers++] = input_handler_hook;
} else {
log_die("Out of memory");
}
patch_x11_event_loop_input_handlers
[patch_x11_event_loop_num_input_handlers++] = input_handler_hook;
} else {
log_die("Out of memory");
}
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
pthread_mutex_unlock(&patch_x11_event_loop_input_handlers_lock);
log_debug("Added input handler %p of lib %s", input_handler_hook, lib_with_handler_impl);
log_debug(
"Added input handler %p of lib %s",
input_handler_hook,
lib_with_handler_impl);
}
+8 -5
View File
@@ -2,17 +2,20 @@
#define PROHOOK_X11_EVENT_LOOP_H
/**
* Initialize this module which re-implements a X11 event loop processing keyboard button presses and releases.
* This is required for Pro 1/2 because the game has all X11 input handling removed. Therefore, we cannot use any
* Initialize this module which re-implements a X11 event loop processing
* keyboard button presses and releases. This is required for Pro 1/2 because
* the game has all X11 input handling removed. Therefore, we cannot use any
* ptapi io implementations using X11, e.g. keyboard inputs.
*/
void patch_x11_event_loop_init();
/**
* Register a handler (multiple possible) to receive X11 input events, e.g. key pressed, released
* Register a handler (multiple possible) to receive X11 input events, e.g. key
* pressed, released
*
* @param lib_with_handler_impl Path to a library implementing the x11-input-handler API
* @param lib_with_handler_impl Path to a library implementing the
* x11-input-handler API
*/
void patch_x11_event_loop_add_input_handler(const char* lib_with_handler_impl);
void patch_x11_event_loop_add_input_handler(const char *lib_with_handler_impl);
#endif