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
+15 -14
View File
@@ -27,24 +27,25 @@ const struct util_options_defs hook_core_options_defs = {
// Just use something because this is not relevant/required here
.usage_param = '\r',
.defs = hook_core_options_def,
.ndefs = lengthof(hook_core_options_def)
};
.ndefs = lengthof(hook_core_options_def)};
void hook_core_options_init(int argc, char** argv, struct hook_core_options* options)
void hook_core_options_init(
int argc, char **argv, struct hook_core_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&hook_core_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&hook_core_options_defs);
if (!options_opt) {
return;
}
if (!options_opt) {
return;
}
options->log.file = util_options_get_str(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->log.file = util_options_get_str(
options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
}
+6 -5
View File
@@ -4,12 +4,13 @@
#include "util/log.h"
struct hook_core_options {
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
void hook_core_options_init(int argc, char** argv, struct hook_core_options* options);
void hook_core_options_init(
int argc, char **argv, struct hook_core_options *options);
#endif
+90 -80
View File
@@ -13,121 +13,131 @@
#include "util/str.h"
#include "util/sys-info.h"
static void hook_core_piu_log_application_args(int argc, char** argv)
static void hook_core_piu_log_application_args(int argc, char **argv)
{
const char* sep = "\n";
char* str = util_str_dup("");
char* tmp;
const char *sep = "\n";
char *str = util_str_dup("");
char *tmp;
for (int i = 0; i < argc; i++) {
if (strlen(str) > 0) {
tmp = util_str_merge(str, sep);
free(str);
str = tmp;
}
tmp = util_str_merge(str, argv[i]);
free(str);
str = tmp;
for (int i = 0; i < argc; i++) {
if (strlen(str) > 0) {
tmp = util_str_merge(str, sep);
free(str);
str = tmp;
}
log_info("Application arguments (%d):\n%s", argc, str);
tmp = util_str_merge(str, argv[i]);
free(str);
str = tmp;
}
log_info("Application arguments (%d):\n%s", argc, str);
free(str);
}
void hook_core_piu_log_init(int argc, char** argv)
void hook_core_piu_log_init(int argc, char **argv)
{
struct hook_core_options options;
struct hook_core_options options;
hook_core_options_init(argc, argv, &options);
hook_core_options_init(argc, argv, &options);
util_log_set_file(options.log.file, false);
util_log_set_level(options.log.level);
util_log_set_file(options.log.file, false);
util_log_set_level(options.log.level);
}
void hook_core_piu_log_info(int argc, char** argv)
void hook_core_piu_log_info(int argc, char **argv)
{
log_info("\n"
" _ _ \n"
" _ __ _ _ _ __ ___ _ __ | |_ ___ ___ | |___ \n"
" | '_ \\| | | | '_ ` _ \\| '_ \\| __/ _ \\ / _ \\| / __|\n"
" | |_) | |_| | | | | | | |_) | || (_) | (_) | \\__ \\\n"
" | .__/ \\__,_|_| |_| |_| .__/ \\__\\___/ \\___/|_|___/\n"
" |_| |_| ");
log_info(
"\n"
" _ _ \n"
" _ __ _ _ _ __ ___ _ __ | |_ ___ ___ | |___ \n"
" | '_ \\| | | | '_ ` _ \\| '_ \\| __/ _ \\ / _ \\| / __|\n"
" | |_) | |_| | | | | | | |_) | || (_) | (_) | \\__ \\\n"
" | .__/ \\__,_|_| |_| |_| .__/ \\__\\___/ \\___/|_|___/\n"
" |_| |_| ");
log_info("Pumptools build " __DATE__ " " __TIME__ " gitrev %s", STRINGIFY(GITREV));
log_info(
"Pumptools build " __DATE__ " " __TIME__ " gitrev %s", STRINGIFY(GITREV));
util_sys_info_log();
util_proc_log_info();
util_glibc_info_log();
hook_core_piu_log_application_args(argc, argv);
util_sys_info_log();
util_proc_log_info();
util_glibc_info_log();
hook_core_piu_log_application_args(argc, argv);
}
char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv)
char *hook_core_piu_utils_get_and_verify_game_data_path(int argc, char **argv)
{
if (argc < 2) {
log_error("Missing game data path, usage for piu (stock args): piu <game folder> (e.g. piu ./game)");
exit(0);
}
if (argc < 2) {
log_error(
"Missing game data path, usage for piu (stock args): piu <game folder> "
"(e.g. piu ./game)");
exit(0);
}
char* game_data_path = util_str_dup(argv[1]);
char *game_data_path = util_str_dup(argv[1]);
log_info("Game data path: %s", game_data_path);
log_info("Game data path: %s", game_data_path);
/* remove trailing / for the hook. however, the game crashes without it */
if (util_str_ends_with(game_data_path, "/")) {
game_data_path[strlen(game_data_path) - 1] = '\0';
} else {
log_error("Game data path '%s' does not end with a trailing /, exiting because the game is going to "
"crash anyway!", game_data_path);
exit(0);
}
/* remove trailing / for the hook. however, the game crashes without it */
if (util_str_ends_with(game_data_path, "/")) {
game_data_path[strlen(game_data_path) - 1] = '\0';
} else {
log_error(
"Game data path '%s' does not end with a trailing /, exiting because "
"the game is going to "
"crash anyway!",
game_data_path);
exit(0);
}
/* depending on the version, the game also just crashes if the game folder or files within it were not found */
if (!util_fs_path_exists(game_data_path)) {
log_error("Game data path '%s' does not exist, exiting", game_data_path);
exit(0);
}
/* depending on the version, the game also just crashes if the game folder or
* files within it were not found */
if (!util_fs_path_exists(game_data_path)) {
log_error("Game data path '%s' does not exist, exiting", game_data_path);
exit(0);
}
return game_data_path;
return game_data_path;
}
void hook_core_piu_utils_verify_root_user()
{
log_info("Verifying process is running as root user.");
log_info("Verifying process is running as root user.");
if (!util_proc_is_running_as_root()) {
log_error("Process not running as root which is required for the game to work correctly.");
//exit(0);
}
if (!util_proc_is_running_as_root()) {
log_error(
"Process not running as root which is required for the game to work "
"correctly.");
// exit(0);
}
}
void hook_core_piu_utils_fix_locale()
{
log_info("Fixing locale settings.");
log_info("Fixing locale settings.");
if (setenv("LC_ALL", "C", 1) != 0) {
log_warn("Setting locale LC_ALL failed.");
}
if (setenv("LC_ALL", "C", 1) != 0) {
log_warn("Setting locale LC_ALL failed.");
}
if (unsetenv("LANGUAGE") != 0) {
log_warn("Unsetting LANGUAGE env var failed.");
}
if (unsetenv("LANGUAGE") != 0) {
log_warn("Unsetting LANGUAGE env var failed.");
}
}
bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv)
bool hook_core_piu_block_non_piu_process_recursion(int argc, char **argv)
{
/* Sanity check for arguments. If further child processes are started
from the current process, and using LD_PRELOAD on the current process,
all children are also getting the preloaded library. This causes
multiple calls to the trap main function and just crashes our
application at some point.
The executable file is required to contain the "piu" substring to make
this work properly */
if (!strstr(argv[0], "piu")) {
log_warn("Not attaching to non piu process %s", argv[0]);
return true;
} else {
return false;
}
/* Sanity check for arguments. If further child processes are started
from the current process, and using LD_PRELOAD on the current process,
all children are also getting the preloaded library. This causes
multiple calls to the trap main function and just crashes our
application at some point.
The executable file is required to contain the "piu" substring to make
this work properly */
if (!strstr(argv[0], "piu")) {
log_warn("Not attaching to non piu process %s", argv[0]);
return true;
} else {
return false;
}
}
+12 -10
View File
@@ -2,14 +2,15 @@
#define HOOK_CORE_PIU_UTILS_H
/**
* Initialize the logging system as early as possible to allow recording everything to a log file as well.
* Initialize the logging system as early as possible to allow recording
* everything to a log file as well.
*/
void hook_core_piu_log_init(int argc, char** argv);
void hook_core_piu_log_init(int argc, char **argv);
/**
* Log process and system relevant information.
*/
void hook_core_piu_log_info(int argc, char** argv);
void hook_core_piu_log_info(int argc, char **argv);
/**
* Check and verify the game data path argument passed to the game via argv
@@ -19,9 +20,10 @@ void hook_core_piu_log_info(int argc, char** argv);
*
* @param argc Argc from piu main
* @param argv Argv from piu main
* @return New string with game data path extracted from argv (caller has to free)
* @return New string with game data path extracted from argv (caller has to
* free)
*/
char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv);
char *hook_core_piu_utils_get_and_verify_game_data_path(int argc, char **argv);
/**
* Verify that the current process is running as root user because the game
@@ -38,16 +40,16 @@ void hook_core_piu_utils_fix_locale();
/**
* If further child processes are started from the current process, and using
* LD_PRELOAD on the current process, all children are also getting the preloaded
* library. This causes multiple calls to the trap main function and just crashes our
* application at some point. The executable file is required to contain the "piu"
* substring to make this work properly.
* LD_PRELOAD on the current process, all children are also getting the
* preloaded library. This causes multiple calls to the trap main function and
* just crashes our application at some point. The executable file is required
* to contain the "piu" substring to make this work properly.
*
* @param argc Argc from piu main
* @param argv Argv from piu main
* @return True if we have to block this call by another process,
* false if the process calling this is the piu process.
*/
bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv);
bool hook_core_piu_block_non_piu_process_recursion(int argc, char **argv);
#endif
+74 -62
View File
@@ -10,89 +10,101 @@
#include "util/log.h"
#include "util/patch.h"
static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len);
static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len);
static int32_t exchook_eeprom_read(uint8_t *buffer, int32_t len);
static int32_t exchook_eeprom_write(const uint8_t *buffer, int32_t len);
static char* exchook_eeprom_file;
static char *exchook_eeprom_file;
static uint8_t exchook_eeprom_buffer[8192];
void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file)
void exchook_eeprom_init(
const struct exchook_mempatch_table *patch_table, const char *eeprom_file)
{
void* buffer;
size_t len;
void *buffer;
size_t len;
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
/* EEPROM file does not exist, create new */
if (!exchook_eeprom_file) {
memset(exchook_eeprom_buffer, 0xFF, sizeof(exchook_eeprom_buffer));
FILE *file = fopen(eeprom_file, "wb+");
if (file == NULL) {
log_error(
"Creating new eeprom file %s failed: %s",
eeprom_file,
strerror(errno));
}
fwrite(exchook_eeprom_buffer, sizeof(exchook_eeprom_buffer), 1, file);
fclose(file);
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
len = (size_t) -1;
} else {
if (util_file_load(exchook_eeprom_file, &buffer, &len, false)) {
if (len > sizeof(exchook_eeprom_buffer)) {
log_error(
"Contents of %s eeprom file exceed the max eeprom buffer "
" size of %d bytes",
eeprom_file,
sizeof(exchook_eeprom_buffer));
free(buffer);
return;
}
/* EEPROM file does not exist, create new */
if (!exchook_eeprom_file) {
memset(exchook_eeprom_buffer, 0xFF, sizeof(exchook_eeprom_buffer));
FILE* file = fopen(eeprom_file, "wb+");
if (file == NULL) {
log_error("Creating new eeprom file %s failed: %s", eeprom_file, strerror(errno));
}
fwrite(exchook_eeprom_buffer, sizeof(exchook_eeprom_buffer), 1, file);
fclose(file);
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
len = (size_t) -1;
/* copy read contents */
memcpy(exchook_eeprom_buffer, buffer, len);
free(buffer);
} else {
if (util_file_load(exchook_eeprom_file, &buffer, &len, false)) {
if (len > sizeof(exchook_eeprom_buffer)) {
log_error("Contents of %s eeprom file exceed the max eeprom buffer "
" size of %d bytes", eeprom_file,
sizeof(exchook_eeprom_buffer));
free(buffer);
return;
}
/* copy read contents */
memcpy(exchook_eeprom_buffer, buffer, len);
free(buffer);
} else {
log_error("Loading eeprom file %s failed", exchook_eeprom_file);
}
log_error("Loading eeprom file %s failed", exchook_eeprom_file);
}
}
log_assert(exchook_eeprom_file);
log_assert(exchook_eeprom_file);
/* Hook eeprom */
util_patch_function(patch_table->addr_eeprom_read, exchook_eeprom_read);
util_patch_function(patch_table->addr_eeprom_write, exchook_eeprom_write);
/* Hook eeprom */
util_patch_function(patch_table->addr_eeprom_read, exchook_eeprom_read);
util_patch_function(patch_table->addr_eeprom_write, exchook_eeprom_write);
log_info("Initizlied (%s), eeprom file %s", len == -1 ? "new" : "loaded", eeprom_file);
log_info(
"Initizlied (%s), eeprom file %s",
len == -1 ? "new" : "loaded",
eeprom_file);
}
static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len)
static int32_t exchook_eeprom_read(uint8_t *buffer, int32_t len)
{
if (len > sizeof(exchook_eeprom_buffer)) {
log_error("Eeprom read %d exceeds buffer size %d", len,
sizeof(exchook_eeprom_buffer));
return 0;
}
if (len > sizeof(exchook_eeprom_buffer)) {
log_error(
"Eeprom read %d exceeds buffer size %d",
len,
sizeof(exchook_eeprom_buffer));
return 0;
}
memcpy(buffer, exchook_eeprom_buffer, len);
memcpy(buffer, exchook_eeprom_buffer, len);
return len;
return len;
}
static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len)
static int32_t exchook_eeprom_write(const uint8_t *buffer, int32_t len)
{
if (len > sizeof(exchook_eeprom_buffer)) {
log_error("Eeprom write %d exceeds buffer size %d", len,
sizeof(exchook_eeprom_buffer));
return 0;
}
if (len > sizeof(exchook_eeprom_buffer)) {
log_error(
"Eeprom write %d exceeds buffer size %d",
len,
sizeof(exchook_eeprom_buffer));
return 0;
}
memcpy(exchook_eeprom_buffer, buffer, len);
memcpy(exchook_eeprom_buffer, buffer, len);
/* Write back to file */
if (!util_file_save(exchook_eeprom_file, exchook_eeprom_buffer, len)) {
log_error("Storing eeprom contents to file %s failed",
exchook_eeprom_file);
}
/* Write back to file */
if (!util_file_save(exchook_eeprom_file, exchook_eeprom_buffer, len)) {
log_error("Storing eeprom contents to file %s failed", exchook_eeprom_file);
}
return len;
return len;
}
+2 -1
View File
@@ -14,6 +14,7 @@
* @param eeprom_file Path to existing eeprom file to read from and new eeprom
* file to store to
*/
void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file);
void exchook_eeprom_init(
const struct exchook_mempatch_table *patch_table, const char *eeprom_file);
#endif
+413 -405
View File
@@ -11,54 +11,53 @@
#include "util/patch.h"
/* Taken from ioarcade.hpp nx2 src dump */
#define GI_P1_1 0x00000001
#define GI_P1_3 0x00000002
#define GI_P1_5 0x00000004
#define GI_P1_7 0x00000008
#define GI_P1_9 0x00000010
#define GI_P1_1 0x00000001
#define GI_P1_3 0x00000002
#define GI_P1_5 0x00000004
#define GI_P1_7 0x00000008
#define GI_P1_9 0x00000010
#define GI_P2_1 0x00000100
#define GI_P2_3 0x00000200
#define GI_P2_5 0x00000400
#define GI_P2_7 0x00000800
#define GI_P2_9 0x00001000
#define GI_P2_1 0x00000100
#define GI_P2_3 0x00000200
#define GI_P2_5 0x00000400
#define GI_P2_7 0x00000800
#define GI_P2_9 0x00001000
#define GI_TEST 0x00010000
#define GI_SERVICE 0x00020000
#define GI_CLEAR 0x00040000
#define GI_TEST 0x00010000
#define GI_SERVICE 0x00020000
#define GI_CLEAR 0x00040000
#define GI_COIN 0x00100000
#define GI_COIN2 0x00200000
#define GI_COIN 0x00100000
#define GI_COIN2 0x00200000
struct exchook_io_sensores {
uint32_t lu : 4;
uint32_t ru : 4;
uint32_t cn : 4;
uint32_t ld : 4;
uint32_t rd : 4;
uint32_t padding : 12;
uint32_t lu : 4;
uint32_t ru : 4;
uint32_t cn : 4;
uint32_t ld : 4;
uint32_t rd : 4;
uint32_t padding : 12;
};
static const uint8_t exchook_io_sensor_mappings[] = {
1, 2, 3, 0
};
static const uint8_t exchook_io_sensor_mappings[] = {1, 2, 3, 0};
static struct ptapi_io_piuio_api exchook_piuio_api;
static uint16_t exchook_io_check(void* obj);
static int32_t exchook_io_light_all(void* obj, uint8_t on);
static int32_t exchook_io_light_neon(void* obj, uint8_t on);
static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id);
static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd);
static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd);
static int32_t exchook_io_input(void* obj);
static int32_t exchook_io_coin_input(void* obj);
static int32_t exchook_io_coin_input_2(void* obj);
static int32_t exchook_io_coin_counter_2(void* obj);
static uint16_t exchook_io_check(void *obj);
static int32_t exchook_io_light_all(void *obj, uint8_t on);
static int32_t exchook_io_light_neon(void *obj, uint8_t on);
static int32_t
exchook_io_light_halogan(void *obj, uint8_t on, uint16_t light_id);
static int32_t exchook_io_light_p1_ccfl(void *obj, uint8_t on, uint16_t cmd);
static int32_t exchook_io_light_p2_ccfl(void *obj, uint8_t on, uint16_t cmd);
static int32_t exchook_io_input(void *obj);
static int32_t exchook_io_coin_input(void *obj);
static int32_t exchook_io_coin_input_2(void *obj);
static int32_t exchook_io_coin_counter_2(void *obj);
static uint32_t* exchook_io_game_input_stat;
static uint32_t* exchook_io_game_input_down;
static uint32_t* exchook_io_game_input_up;
static uint32_t *exchook_io_game_input_stat;
static uint32_t *exchook_io_game_input_down;
static uint32_t *exchook_io_game_input_up;
static uint32_t exchook_io_game_input_stat_prev;
@@ -72,434 +71,443 @@ static struct ptapi_io_piuio_cab_outputs exchook_io_out_cab;
static bool exchook_io_exit_on_service_test;
void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path,
bool exit_on_service_test)
void exchook_io_init(
const struct exchook_mempatch_table *patch_table,
const char *piuio_lib_path,
bool exit_on_service_test)
{
if (!piuio_lib_path) {
log_error("NULL piuio (emu) lib path. Check that you have set-up and configured a piuio API implementation "
"correctly.");
return;
}
if (!piuio_lib_path) {
log_error(
"NULL piuio (emu) lib path. Check that you have set-up and configured "
"a piuio API implementation "
"correctly.");
return;
}
/* 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, &exchook_piuio_api)) {
log_error("Loading piuio API from file %s failed", piuio_lib_path);
return;
}
if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &exchook_piuio_api)) {
log_error("Loading piuio API from file %s failed", piuio_lib_path);
return;
}
exchook_io_exit_on_service_test = exit_on_service_test;
exchook_io_exit_on_service_test = exit_on_service_test;
log_info("Service + Test exit %d", exchook_io_exit_on_service_test);
log_info("Service + Test exit %d", exchook_io_exit_on_service_test);
/* Hook MK5IO engine calls */
/* Why so many functions you might ask? Because the MK5 IO code is a pile
of shit created by a monkey */
/* Hook MK5IO engine calls */
/* Why so many functions you might ask? Because the MK5 IO code is a pile
of shit created by a monkey */
util_patch_function(patch_table->addr_io_check, exchook_io_check);
util_patch_function(patch_table->addr_io_light_all, exchook_io_light_all);
util_patch_function(patch_table->addr_io_light_neon, exchook_io_light_neon);
util_patch_function(patch_table->addr_io_light_halogan, exchook_io_light_halogan);
util_patch_function(patch_table->addr_io_light_p1_ccfl, exchook_io_light_p1_ccfl);
util_patch_function(patch_table->addr_io_light_p2_ccfl, exchook_io_light_p2_ccfl);
util_patch_function(patch_table->addr_io_input, exchook_io_input);
util_patch_function(patch_table->addr_io_coin_input, exchook_io_coin_input);
util_patch_function(patch_table->addr_io_coin_input_2, exchook_io_coin_input_2);
util_patch_function(patch_table->addr_io_coin_counter_2, exchook_io_coin_counter_2);
util_patch_function(patch_table->addr_io_check, exchook_io_check);
util_patch_function(patch_table->addr_io_light_all, exchook_io_light_all);
util_patch_function(patch_table->addr_io_light_neon, exchook_io_light_neon);
util_patch_function(
patch_table->addr_io_light_halogan, exchook_io_light_halogan);
util_patch_function(
patch_table->addr_io_light_p1_ccfl, exchook_io_light_p1_ccfl);
util_patch_function(
patch_table->addr_io_light_p2_ccfl, exchook_io_light_p2_ccfl);
util_patch_function(patch_table->addr_io_input, exchook_io_input);
util_patch_function(patch_table->addr_io_coin_input, exchook_io_coin_input);
util_patch_function(
patch_table->addr_io_coin_input_2, exchook_io_coin_input_2);
util_patch_function(
patch_table->addr_io_coin_counter_2, exchook_io_coin_counter_2);
exchook_io_game_input_stat = ((uint32_t*) patch_table->addr_io_game_input_stat);
exchook_io_game_input_down = ((uint32_t*) patch_table->addr_io_game_input_down);
exchook_io_game_input_up = ((uint32_t*) patch_table->addr_io_game_input_up);
exchook_io_game_input_stat =
((uint32_t *) patch_table->addr_io_game_input_stat);
exchook_io_game_input_down =
((uint32_t *) patch_table->addr_io_game_input_down);
exchook_io_game_input_up = ((uint32_t *) patch_table->addr_io_game_input_up);
/* there is an io init method but obviously requires another address to be
hooked...just init our backend here */
if (!exchook_piuio_api.open()) {
log_error("Opening io failed");
return;
}
/* there is an io init method but obviously requires another address to be
hooked...just init our backend here */
if (!exchook_piuio_api.open()) {
log_error("Opening io failed");
return;
}
log_info("Initialized");
log_info("Initialized");
}
void exchook_io_shutdown(void)
{
}
/* check? why can't you just call it get_fucking_inputs... */
static uint16_t exchook_io_check(void* obj)
static uint16_t exchook_io_check(void *obj)
{
struct ptapi_io_piuio_pad_inputs p1_pad_in;
struct ptapi_io_piuio_pad_inputs p2_pad_in;
struct ptapi_io_piuio_pad_inputs p1_pad_in;
struct ptapi_io_piuio_pad_inputs p2_pad_in;
/* Sensor states are expected to be returned using the object */
struct exchook_io_sensores* sensores_p1 =
(struct exchook_io_sensores*) obj;
struct exchook_io_sensores* sensores_p2 =
(struct exchook_io_sensores*) (((uint32_t*) obj) + 1);
/* Sensor states are expected to be returned using the object */
struct exchook_io_sensores *sensores_p1 = (struct exchook_io_sensores *) obj;
struct exchook_io_sensores *sensores_p2 =
(struct exchook_io_sensores *) (((uint32_t *) obj) + 1);
/* execute polling here */
/* execute polling here */
/* might delay output for a frame but whatever */
if (!exchook_piuio_api.send()) {
log_error("Piuio send failed");
}
/* might delay output for a frame but whatever */
if (!exchook_piuio_api.send()) {
log_error("Piuio send failed");
}
if (!exchook_piuio_api.recv()) {
log_error("Piuio receive failed");
}
if (!exchook_piuio_api.recv()) {
log_error("Piuio receive failed");
}
/* MK5 inputs state reset */
exchook_io_sensores_p1.lu = 0;
exchook_io_sensores_p1.ru = 0;
exchook_io_sensores_p1.cn = 0;
exchook_io_sensores_p1.ld = 0;
exchook_io_sensores_p1.rd = 0;
/* MK5 inputs state reset */
exchook_io_sensores_p1.lu = 0;
exchook_io_sensores_p1.ru = 0;
exchook_io_sensores_p1.cn = 0;
exchook_io_sensores_p1.ld = 0;
exchook_io_sensores_p1.rd = 0;
exchook_io_sensores_p2.lu = 0;
exchook_io_sensores_p2.ru = 0;
exchook_io_sensores_p2.cn = 0;
exchook_io_sensores_p2.ld = 0;
exchook_io_sensores_p2.rd = 0;
exchook_io_sensores_p2.lu = 0;
exchook_io_sensores_p2.ru = 0;
exchook_io_sensores_p2.cn = 0;
exchook_io_sensores_p2.ld = 0;
exchook_io_sensores_p2.rd = 0;
// State reset
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
// State reset
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
/* cycle all sensores */
for (uint8_t i = 0; i < 4; i++) {
exchook_piuio_api.get_input_pad(0, i, &p1_pad_in);
exchook_piuio_api.get_input_pad(1, i, &p2_pad_in);
/* cycle all sensores */
for (uint8_t i = 0; i < 4; i++) {
exchook_piuio_api.get_input_pad(0, i, &p1_pad_in);
exchook_piuio_api.get_input_pad(1, i, &p2_pad_in);
/* process inputs */
/* Player 1 */
if (p1_pad_in.lu) {
exchook_io_sensores_p1.lu |= (1 << exchook_io_sensor_mappings[i]);
}
if (p1_pad_in.ru) {
exchook_io_sensores_p1.ru |= (1 << exchook_io_sensor_mappings[i]);
}
if (p1_pad_in.cn) {
exchook_io_sensores_p1.cn |= (1 << exchook_io_sensor_mappings[i]);
}
if (p1_pad_in.ld) {
exchook_io_sensores_p1.ld |= (1 << exchook_io_sensor_mappings[i]);
}
if (p1_pad_in.rd) {
exchook_io_sensores_p1.rd |= (1 << exchook_io_sensor_mappings[i]);
}
/* Player 2 */
if (p2_pad_in.lu) {
exchook_io_sensores_p2.lu |= (1 << exchook_io_sensor_mappings[i]);
}
if (p2_pad_in.ru) {
exchook_io_sensores_p2.ru |= (1 << exchook_io_sensor_mappings[i]);
}
if (p2_pad_in.cn) {
exchook_io_sensores_p2.cn |= (1 << exchook_io_sensor_mappings[i]);
}
if (p2_pad_in.ld) {
exchook_io_sensores_p2.ld |= (1 << exchook_io_sensor_mappings[i]);
}
if (p2_pad_in.rd) {
exchook_io_sensores_p2.rd |= (1 << exchook_io_sensor_mappings[i]);
}
}
memcpy(sensores_p1, &exchook_io_sensores_p1, sizeof(exchook_io_sensores_p1));
memcpy(sensores_p2, &exchook_io_sensores_p2, sizeof(exchook_io_sensores_p2));
return 0;
}
static int32_t exchook_io_light_all(void* obj, uint8_t on)
{
if (on) {
memset(&exchook_io_out_pad_p1, 1, sizeof(exchook_io_out_pad_p1));
memset(&exchook_io_out_pad_p2, 1, sizeof(exchook_io_out_pad_p2));
memset(&exchook_io_out_cab, 1, sizeof(exchook_io_out_cab));
} else {
memset(&exchook_io_out_pad_p1, 0, sizeof(exchook_io_out_pad_p1));
memset(&exchook_io_out_pad_p2, 0, sizeof(exchook_io_out_pad_p2));
memset(&exchook_io_out_cab, 0, sizeof(exchook_io_out_cab));
}
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_p1);
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_p2);
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_light_neon(void* obj, uint8_t on)
{
if (on) {
exchook_io_out_cab.bass = true;
} else {
exchook_io_out_cab.bass = false;
}
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id)
{
if (light_id & 0x0400) {
exchook_io_out_cab.halo_l1 = on;
}
if (light_id & 0x0200) {
exchook_io_out_cab.halo_l2 = on;
}
if (light_id & 0x0100) {
exchook_io_out_cab.halo_r1 = on;
}
if (light_id & 0x0080) {
exchook_io_out_cab.halo_r2 = on;
}
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd)
{
if (cmd & 0x0004) {
exchook_io_out_pad_p1.lu = on;
}
if (cmd & 0x0008) {
exchook_io_out_pad_p1.ru = on;
}
if (cmd & 0x0010) {
exchook_io_out_pad_p1.cn = on;
}
if (cmd & 0x0020) {
exchook_io_out_pad_p1.ld = on;
}
if (cmd & 0x040) {
exchook_io_out_pad_p1.rd = on;
}
return 0;
}
static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd)
{
if (cmd & 0x0004) {
exchook_io_out_pad_p2.lu = on;
}
if (cmd & 0x0008) {
exchook_io_out_pad_p2.ru = on;
}
if (cmd & 0x0010) {
exchook_io_out_pad_p2.cn = on;
}
if (cmd & 0x0020) {
exchook_io_out_pad_p2.ld = on;
}
if (cmd & 0x040) {
exchook_io_out_pad_p2.rd = on;
}
return 0;
}
static int32_t exchook_io_input(void* obj)
{
uint32_t stat;
uint32_t stat_down;
uint32_t stat_up;
struct ptapi_io_piuio_sys_inputs sys_in;
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
exchook_piuio_api.get_input_sys(&sys_in);
/* For game loaders and stuff */
if (exchook_io_exit_on_service_test) {
if (sys_in.test && sys_in.service) {
log_info("Exit on service + test enabled and hit, bye");
exit(0);
}
}
/* process final input states for the game as well as service, test, clear
and coin which can't be handled in the check function */
stat = 0;
stat_down = 0;
stat_up = 0;
/* process inputs */
/* Player 1 */
if (exchook_io_sensores_p1.lu) {
stat |= GI_P1_7;
if (p1_pad_in.lu) {
exchook_io_sensores_p1.lu |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p1.ru) {
stat |= GI_P1_9;
if (p1_pad_in.ru) {
exchook_io_sensores_p1.ru |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p1.cn) {
stat |= GI_P1_5;
if (p1_pad_in.cn) {
exchook_io_sensores_p1.cn |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p1.ld) {
stat |= GI_P1_1;
if (p1_pad_in.ld) {
exchook_io_sensores_p1.ld |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p1.rd) {
stat |= GI_P1_3;
if (p1_pad_in.rd) {
exchook_io_sensores_p1.rd |= (1 << exchook_io_sensor_mappings[i]);
}
/* Player 2 */
if (exchook_io_sensores_p2.lu) {
stat |= GI_P2_7;
/* Player 2 */
if (p2_pad_in.lu) {
exchook_io_sensores_p2.lu |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p2.ru) {
stat |= GI_P2_9;
if (p2_pad_in.ru) {
exchook_io_sensores_p2.ru |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p2.cn) {
stat |= GI_P2_5;
if (p2_pad_in.cn) {
exchook_io_sensores_p2.cn |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p2.ld) {
stat |= GI_P2_1;
if (p2_pad_in.ld) {
exchook_io_sensores_p2.ld |= (1 << exchook_io_sensor_mappings[i]);
}
if (exchook_io_sensores_p2.rd) {
stat |= GI_P2_3;
if (p2_pad_in.rd) {
exchook_io_sensores_p2.rd |= (1 << exchook_io_sensor_mappings[i]);
}
}
/* Sys */
if (sys_in.test) {
stat |= GI_TEST;
}
memcpy(sensores_p1, &exchook_io_sensores_p1, sizeof(exchook_io_sensores_p1));
memcpy(sensores_p2, &exchook_io_sensores_p2, sizeof(exchook_io_sensores_p2));
if (sys_in.service) {
stat |= GI_SERVICE;
}
/* Taken from source but doesn't seem to work (on some versions?) */
if (sys_in.clear) {
stat |= GI_CLEAR;
}
if (sys_in.coin) {
stat |= GI_COIN;
}
if (sys_in.coin2) {
stat |= GI_COIN2;
}
/* iterate bits for up and down events */
for (uint8_t i = 0; i < 32; i++) {
if (!(exchook_io_game_input_stat_prev & (1 << i)) &&
(stat & (1 << i))) {
/* New push down */
stat_down |= (1 << i);
} else if ((exchook_io_game_input_stat_prev & (1 << i)) &&
!(stat & (1 << i))) {
/* New release */
stat_up |= (1 << i);
}
}
/* Extremely bad IO subsystem design */
*exchook_io_game_input_stat |= stat;
*exchook_io_game_input_down |= stat_down;
*exchook_io_game_input_up = stat_up;
/* swap for next iterateion */
exchook_io_game_input_stat_prev = *exchook_io_game_input_stat;
/* Welp, the game expects us to do output setting if a button is pressed
here...fuck that mess. Merge (i.e. |= not =) with other states set
by the game */
memset(&exchook_io_out_pad_press_p1, 0, sizeof(exchook_io_out_pad_press_p1));
memset(&exchook_io_out_pad_press_p2, 0, sizeof(exchook_io_out_pad_press_p2));
/* Player 1 */
exchook_io_out_pad_press_p1.lu |= exchook_io_sensores_p1.lu;
exchook_io_out_pad_press_p1.ru |= exchook_io_sensores_p1.ru;
exchook_io_out_pad_press_p1.cn |= exchook_io_sensores_p1.cn;
exchook_io_out_pad_press_p1.ld |= exchook_io_sensores_p1.ld;
exchook_io_out_pad_press_p1.rd |= exchook_io_sensores_p1.rd;
/* Player 2 */
exchook_io_out_pad_press_p2.lu |= exchook_io_sensores_p2.lu;
exchook_io_out_pad_press_p2.ru |= exchook_io_sensores_p2.ru;
exchook_io_out_pad_press_p2.cn |= exchook_io_sensores_p2.cn;
exchook_io_out_pad_press_p2.ld |= exchook_io_sensores_p2.ld;
exchook_io_out_pad_press_p2.rd |= exchook_io_sensores_p2.rd;
/* merge */
/* Player 1 */
exchook_io_out_pad_press_p1.lu |= exchook_io_out_pad_p1.lu;
exchook_io_out_pad_press_p1.ru |= exchook_io_out_pad_p1.ru;
exchook_io_out_pad_press_p1.cn |= exchook_io_out_pad_p1.cn;
exchook_io_out_pad_press_p1.ld |= exchook_io_out_pad_p1.ld;
exchook_io_out_pad_press_p1.rd |= exchook_io_out_pad_p1.rd;
/* Player 2 */
exchook_io_out_pad_press_p2.lu |= exchook_io_out_pad_p2.lu;
exchook_io_out_pad_press_p2.ru |= exchook_io_out_pad_p2.ru;
exchook_io_out_pad_press_p2.cn |= exchook_io_out_pad_p2.cn;
exchook_io_out_pad_press_p2.ld |= exchook_io_out_pad_p2.ld;
exchook_io_out_pad_press_p2.rd |= exchook_io_out_pad_p2.rd;
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_press_p1);
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_press_p2);
return 0;
return 0;
}
static int32_t exchook_io_coin_input(void* obj)
static int32_t exchook_io_light_all(void *obj, uint8_t on)
{
/* Stub */
if (on) {
memset(&exchook_io_out_pad_p1, 1, sizeof(exchook_io_out_pad_p1));
memset(&exchook_io_out_pad_p2, 1, sizeof(exchook_io_out_pad_p2));
memset(&exchook_io_out_cab, 1, sizeof(exchook_io_out_cab));
} else {
memset(&exchook_io_out_pad_p1, 0, sizeof(exchook_io_out_pad_p1));
memset(&exchook_io_out_pad_p2, 0, sizeof(exchook_io_out_pad_p2));
memset(&exchook_io_out_cab, 0, sizeof(exchook_io_out_cab));
}
return 0;
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_p1);
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_p2);
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_coin_input_2(void* obj)
static int32_t exchook_io_light_neon(void *obj, uint8_t on)
{
/* Stub */
if (on) {
exchook_io_out_cab.bass = true;
} else {
exchook_io_out_cab.bass = false;
}
return 0;
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_coin_counter_2(void* obj)
static int32_t
exchook_io_light_halogan(void *obj, uint8_t on, uint16_t light_id)
{
/* Stub */
if (light_id & 0x0400) {
exchook_io_out_cab.halo_l1 = on;
}
return 0;
if (light_id & 0x0200) {
exchook_io_out_cab.halo_l2 = on;
}
if (light_id & 0x0100) {
exchook_io_out_cab.halo_r1 = on;
}
if (light_id & 0x0080) {
exchook_io_out_cab.halo_r2 = on;
}
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
return 0;
}
static int32_t exchook_io_light_p1_ccfl(void *obj, uint8_t on, uint16_t cmd)
{
if (cmd & 0x0004) {
exchook_io_out_pad_p1.lu = on;
}
if (cmd & 0x0008) {
exchook_io_out_pad_p1.ru = on;
}
if (cmd & 0x0010) {
exchook_io_out_pad_p1.cn = on;
}
if (cmd & 0x0020) {
exchook_io_out_pad_p1.ld = on;
}
if (cmd & 0x040) {
exchook_io_out_pad_p1.rd = on;
}
return 0;
}
static int32_t exchook_io_light_p2_ccfl(void *obj, uint8_t on, uint16_t cmd)
{
if (cmd & 0x0004) {
exchook_io_out_pad_p2.lu = on;
}
if (cmd & 0x0008) {
exchook_io_out_pad_p2.ru = on;
}
if (cmd & 0x0010) {
exchook_io_out_pad_p2.cn = on;
}
if (cmd & 0x0020) {
exchook_io_out_pad_p2.ld = on;
}
if (cmd & 0x040) {
exchook_io_out_pad_p2.rd = on;
}
return 0;
}
static int32_t exchook_io_input(void *obj)
{
uint32_t stat;
uint32_t stat_down;
uint32_t stat_up;
struct ptapi_io_piuio_sys_inputs sys_in;
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
exchook_piuio_api.get_input_sys(&sys_in);
/* For game loaders and stuff */
if (exchook_io_exit_on_service_test) {
if (sys_in.test && sys_in.service) {
log_info("Exit on service + test enabled and hit, bye");
exit(0);
}
}
/* process final input states for the game as well as service, test, clear
and coin which can't be handled in the check function */
stat = 0;
stat_down = 0;
stat_up = 0;
/* Player 1 */
if (exchook_io_sensores_p1.lu) {
stat |= GI_P1_7;
}
if (exchook_io_sensores_p1.ru) {
stat |= GI_P1_9;
}
if (exchook_io_sensores_p1.cn) {
stat |= GI_P1_5;
}
if (exchook_io_sensores_p1.ld) {
stat |= GI_P1_1;
}
if (exchook_io_sensores_p1.rd) {
stat |= GI_P1_3;
}
/* Player 2 */
if (exchook_io_sensores_p2.lu) {
stat |= GI_P2_7;
}
if (exchook_io_sensores_p2.ru) {
stat |= GI_P2_9;
}
if (exchook_io_sensores_p2.cn) {
stat |= GI_P2_5;
}
if (exchook_io_sensores_p2.ld) {
stat |= GI_P2_1;
}
if (exchook_io_sensores_p2.rd) {
stat |= GI_P2_3;
}
/* Sys */
if (sys_in.test) {
stat |= GI_TEST;
}
if (sys_in.service) {
stat |= GI_SERVICE;
}
/* Taken from source but doesn't seem to work (on some versions?) */
if (sys_in.clear) {
stat |= GI_CLEAR;
}
if (sys_in.coin) {
stat |= GI_COIN;
}
if (sys_in.coin2) {
stat |= GI_COIN2;
}
/* iterate bits for up and down events */
for (uint8_t i = 0; i < 32; i++) {
if (!(exchook_io_game_input_stat_prev & (1 << i)) && (stat & (1 << i))) {
/* New push down */
stat_down |= (1 << i);
} else if (
(exchook_io_game_input_stat_prev & (1 << i)) && !(stat & (1 << i))) {
/* New release */
stat_up |= (1 << i);
}
}
/* Extremely bad IO subsystem design */
*exchook_io_game_input_stat |= stat;
*exchook_io_game_input_down |= stat_down;
*exchook_io_game_input_up = stat_up;
/* swap for next iterateion */
exchook_io_game_input_stat_prev = *exchook_io_game_input_stat;
/* Welp, the game expects us to do output setting if a button is pressed
here...fuck that mess. Merge (i.e. |= not =) with other states set
by the game */
memset(&exchook_io_out_pad_press_p1, 0, sizeof(exchook_io_out_pad_press_p1));
memset(&exchook_io_out_pad_press_p2, 0, sizeof(exchook_io_out_pad_press_p2));
/* Player 1 */
exchook_io_out_pad_press_p1.lu |= exchook_io_sensores_p1.lu;
exchook_io_out_pad_press_p1.ru |= exchook_io_sensores_p1.ru;
exchook_io_out_pad_press_p1.cn |= exchook_io_sensores_p1.cn;
exchook_io_out_pad_press_p1.ld |= exchook_io_sensores_p1.ld;
exchook_io_out_pad_press_p1.rd |= exchook_io_sensores_p1.rd;
/* Player 2 */
exchook_io_out_pad_press_p2.lu |= exchook_io_sensores_p2.lu;
exchook_io_out_pad_press_p2.ru |= exchook_io_sensores_p2.ru;
exchook_io_out_pad_press_p2.cn |= exchook_io_sensores_p2.cn;
exchook_io_out_pad_press_p2.ld |= exchook_io_sensores_p2.ld;
exchook_io_out_pad_press_p2.rd |= exchook_io_sensores_p2.rd;
/* merge */
/* Player 1 */
exchook_io_out_pad_press_p1.lu |= exchook_io_out_pad_p1.lu;
exchook_io_out_pad_press_p1.ru |= exchook_io_out_pad_p1.ru;
exchook_io_out_pad_press_p1.cn |= exchook_io_out_pad_p1.cn;
exchook_io_out_pad_press_p1.ld |= exchook_io_out_pad_p1.ld;
exchook_io_out_pad_press_p1.rd |= exchook_io_out_pad_p1.rd;
/* Player 2 */
exchook_io_out_pad_press_p2.lu |= exchook_io_out_pad_p2.lu;
exchook_io_out_pad_press_p2.ru |= exchook_io_out_pad_p2.ru;
exchook_io_out_pad_press_p2.cn |= exchook_io_out_pad_p2.cn;
exchook_io_out_pad_press_p2.ld |= exchook_io_out_pad_p2.ld;
exchook_io_out_pad_press_p2.rd |= exchook_io_out_pad_p2.rd;
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_press_p1);
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_press_p2);
return 0;
}
static int32_t exchook_io_coin_input(void *obj)
{
/* Stub */
return 0;
}
static int32_t exchook_io_coin_input_2(void *obj)
{
/* Stub */
return 0;
}
static int32_t exchook_io_coin_counter_2(void *obj)
{
/* Stub */
return 0;
}
+3 -1
View File
@@ -15,7 +15,9 @@
* @param piuio_lib_path Path to piuio lib to use for emulation
* @parma exit_on_service_test Exit the game when pressing service + test
*/
void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path,
void exchook_io_init(
const struct exchook_mempatch_table *patch_table,
const char *piuio_lib_path,
bool exit_on_service_test);
/**
+21 -21
View File
@@ -2,42 +2,42 @@
#include <stdlib.h>
#include "sec/lockchip/lockchip.h"
#include "sec/lockchip/lockchip-defs.h"
#include "sec/lockchip/lockchip.h"
#include "util/log.h"
#include "util/patch.h"
#include "lockchip.h"
static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src,
uint8_t* dest);
static void
exchook_lockchip_dec_chunk(uint8_t len, const uint8_t *src, uint8_t *dest);
void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table)
void exchook_lockchip_init(const struct exchook_mempatch_table *patch_table)
{
sec_lockchip_init(
sec_lockchip_defs_transforms[SEC_LOCK_CHIP_DEFS_GAME_EXCEED]);
sec_lockchip_init(
sec_lockchip_defs_transforms[SEC_LOCK_CHIP_DEFS_GAME_EXCEED]);
/* Hook lockchip */
util_patch_function(patch_table->addr_lockchip_dec_chunk, exchook_lockchip_dec_chunk);
/* Hook lockchip */
util_patch_function(
patch_table->addr_lockchip_dec_chunk, exchook_lockchip_dec_chunk);
log_info("Initialized");
log_info("Initialized");
}
static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src,
uint8_t* dest)
static void
exchook_lockchip_dec_chunk(uint8_t len, const uint8_t *src, uint8_t *dest)
{
sec_lockchip_start();
sec_lockchip_start();
uint8_t last_res = sec_lockchip_step(src[0] ^ 0xFF);
uint8_t last_res = sec_lockchip_step(src[0] ^ 0xFF);
for (size_t i = 1; i < len; i++)
{
uint8_t result = sec_lockchip_step(src[i] ^ 0xFF);
dest[i - 1] = (uint8_t)((last_res >> 3) ^ (result << 5));
last_res = result;
}
for (size_t i = 1; i < len; i++) {
uint8_t result = sec_lockchip_step(src[i] ^ 0xFF);
dest[i - 1] = (uint8_t)((last_res >> 3) ^ (result << 5));
last_res = result;
}
uint8_t last_byte = sec_lockchip_step(0);
dest[len - 1] = (uint8_t)((last_res >> 3) ^ (last_byte << 5));
uint8_t last_byte = sec_lockchip_step(0);
dest[len - 1] = (uint8_t)((last_res >> 3) ^ (last_byte << 5));
}
+1 -1
View File
@@ -14,6 +14,6 @@
*
* @param patch_table Patch table with memory addresses
*/
void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table);
void exchook_lockchip_init(const struct exchook_mempatch_table *patch_table);
#endif
+153 -133
View File
@@ -30,225 +30,245 @@
#include "mempatch.h"
#include "options.h"
static void exchook_bootstrapping(int argc, char** argv, struct exchook_options* options, char** game_data_path)
static void exchook_bootstrapping(
int argc,
char **argv,
struct exchook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!exchook_options_init(argc, argv, options)) {
exit(0);
}
if (!exchook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void exchook_game_version_mempatch_table_init(
struct exchook_options* options,
const struct exchook_mempatch_table** patch_table)
struct exchook_options *options,
const struct exchook_mempatch_table **patch_table)
{
log_assert(options);
log_assert(patch_table);
log_assert(options);
log_assert(patch_table);
if (!options->game.version) {
log_die("No game version specified");
} else {
log_info("Game version configured: %s", options->game.version);
}
if (!options->game.version) {
log_die("No game version specified");
} else {
log_info("Game version configured: %s", options->game.version);
}
*patch_table = exchook_mempatch_get_table(options->game.version);
*patch_table = exchook_mempatch_get_table(options->game.version);
if (*patch_table == NULL) {
log_die("Unsupported game version %s", options->game.version);
}
if (*patch_table == NULL) {
log_die("Unsupported game version %s", options->game.version);
}
}
static void exchook_patch_fs_init(struct exchook_options* options)
static void exchook_patch_fs_init(struct exchook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void exchook_fs_redir_settings(struct exchook_options* options)
static void exchook_fs_redir_settings(struct exchook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char *abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void exchook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
}
static void exchook_patch_gfx_init(struct exchook_options* options)
static void exchook_patch_gfx_init(struct exchook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void exchook_patch_main_loop_init(struct exchook_options* options)
static void exchook_patch_main_loop_init(struct exchook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
true, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void exchook_patch_sound_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
static void exchook_patch_sound_init(
struct exchook_options *options,
const struct exchook_mempatch_table *patch_table)
{
log_assert(options);
log_assert(patch_table);
log_assert(options);
log_assert(patch_table);
/* exceed crashes with its default device hw:0. use dmix instead */
if (strcmp(options->patch.sound.device, "dmix") != 0) {
log_warn("Game might crash with selected sound device %s, use 'dmix' instead if that happens",
options->patch.sound.device);
}
/* exceed crashes with its default device hw:0. use dmix instead */
if (strcmp(options->patch.sound.device, "dmix") != 0) {
log_warn(
"Game might crash with selected sound device %s, use 'dmix' instead if "
"that happens",
options->patch.sound.device);
}
patch_sound_init(options->patch.sound.device);
patch_asound_fix_init();
patch_sound_init(options->patch.sound.device);
patch_asound_fix_init();
/* return from StopAllEffects to avoid killing the sound thread */
util_patch_write_memory_byte(patch_table->addr_stop_all_effects_return, 0xC3);
/* return from StopAllEffects to avoid killing the sound thread */
util_patch_write_memory_byte(patch_table->addr_stop_all_effects_return, 0xC3);
}
static void exchook_patch_sigsegv_init(struct exchook_options* options)
static void exchook_patch_sigsegv_init(struct exchook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void exchook_patch_lockchip_init(const struct exchook_mempatch_table* patch_table)
static void
exchook_patch_lockchip_init(const struct exchook_mempatch_table *patch_table)
{
log_assert(patch_table);
log_assert(patch_table);
exchook_lockchip_init(patch_table);
exchook_lockchip_init(patch_table);
}
static void exchook_patch_eeprom_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
static void exchook_patch_eeprom_init(
struct exchook_options *options,
const struct exchook_mempatch_table *patch_table)
{
log_assert(options);
log_assert(patch_table);
log_assert(options);
log_assert(patch_table);
char* eeprom_path;
char *eeprom_path;
if (options->game.settings) {
char* abs_path = util_fs_get_abs_path(options->game.settings);
if (options->game.settings) {
char *abs_path = util_fs_get_abs_path(options->game.settings);
eeprom_path = util_str_merge(abs_path, "/eeprom.bin");
free(abs_path);
} else {
eeprom_path = util_str_dup("/tmp/eeprom.bin");
log_warn("No settings path specified to store eeprom data, defaulting to %s", eeprom_path);
}
eeprom_path = util_str_merge(abs_path, "/eeprom.bin");
free(abs_path);
} else {
eeprom_path = util_str_dup("/tmp/eeprom.bin");
log_warn(
"No settings path specified to store eeprom data, defaulting to %s",
eeprom_path);
}
exchook_eeprom_init(patch_table, eeprom_path);
free(eeprom_path);
exchook_eeprom_init(patch_table, eeprom_path);
free(eeprom_path);
}
static void exchook_patch_piuio_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
static void exchook_patch_piuio_init(
struct exchook_options *options,
const struct exchook_mempatch_table *patch_table)
{
log_assert(options);
log_assert(patch_table);
log_assert(options);
log_assert(patch_table);
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
exchook_io_init(patch_table, abs_path_iolib, options->patch.piuio.exit_test_serv);
free(abs_path_iolib);
}
exchook_io_init(
patch_table, abs_path_iolib, options->patch.piuio.exit_test_serv);
free(abs_path_iolib);
}
}
void exchook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void exchook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void exchook_trap_before_main(int argc, char** argv)
void exchook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct exchook_options options;
const struct exchook_mempatch_table* mempatch_table;
char *game_data_path;
struct exchook_options options;
const struct exchook_mempatch_table *mempatch_table;
exchook_bootstrapping(argc, argv, &options, &game_data_path);
exchook_game_version_mempatch_table_init(&options, &mempatch_table);
exchook_patch_fs_init(&options);
exchook_fs_redir_settings(&options);
exchook_fs_redir_usb();
exchook_patch_gfx_init(&options);
exchook_patch_main_loop_init(&options);
exchook_patch_sound_init(&options, mempatch_table);
exchook_patch_sigsegv_init(&options);
exchook_patch_lockchip_init(mempatch_table);
exchook_patch_eeprom_init(&options, mempatch_table);
exchook_patch_piuio_init(&options, mempatch_table);
exchook_bootstrapping(argc, argv, &options, &game_data_path);
exchook_game_version_mempatch_table_init(&options, &mempatch_table);
exchook_patch_fs_init(&options);
exchook_fs_redir_settings(&options);
exchook_fs_redir_usb();
exchook_patch_gfx_init(&options);
exchook_patch_main_loop_init(&options);
exchook_patch_sound_init(&options, mempatch_table);
exchook_patch_sigsegv_init(&options);
exchook_patch_lockchip_init(mempatch_table);
exchook_patch_eeprom_init(&options, mempatch_table);
exchook_patch_piuio_init(&options, mempatch_table);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void exchook_trap_after_main(void)
{
exchook_io_shutdown();
exchook_io_shutdown();
}
LIB_MAIN_CONSTRUCTOR(exchook_constructor);
+8 -7
View File
@@ -48,15 +48,16 @@ static const struct exchook_mempatch_table _exchook_mempatch_table[] = {
},
};
const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version)
const struct exchook_mempatch_table *
exchook_mempatch_get_table(const char *version)
{
size_t entries = lengthof(_exchook_mempatch_table);
size_t entries = lengthof(_exchook_mempatch_table);
for (uint32_t i = 0; i < entries; i++) {
if (!strcmp(_exchook_mempatch_table[i].version, version)) {
return &_exchook_mempatch_table[i];
}
for (uint32_t i = 0; i < entries; i++) {
if (!strcmp(_exchook_mempatch_table[i].version, version)) {
return &_exchook_mempatch_table[i];
}
}
return NULL;
return NULL;
}
+20 -19
View File
@@ -4,26 +4,27 @@
#include <stdint.h>
struct exchook_mempatch_table {
const char* version;
uintptr_t addr_eeprom_read;
uintptr_t addr_eeprom_write;
uintptr_t addr_io_check;
uintptr_t addr_io_light_all;
uintptr_t addr_io_light_neon;
uintptr_t addr_io_light_halogan;
uintptr_t addr_io_light_p1_ccfl;
uintptr_t addr_io_light_p2_ccfl;
uintptr_t addr_io_input;
uintptr_t addr_io_coin_input;
uintptr_t addr_io_coin_input_2;
uintptr_t addr_io_coin_counter_2;
uintptr_t addr_io_game_input_stat;
uintptr_t addr_io_game_input_down;
uintptr_t addr_io_game_input_up;
uintptr_t addr_lockchip_dec_chunk;
uintptr_t addr_stop_all_effects_return;
const char *version;
uintptr_t addr_eeprom_read;
uintptr_t addr_eeprom_write;
uintptr_t addr_io_check;
uintptr_t addr_io_light_all;
uintptr_t addr_io_light_neon;
uintptr_t addr_io_light_halogan;
uintptr_t addr_io_light_p1_ccfl;
uintptr_t addr_io_light_p2_ccfl;
uintptr_t addr_io_input;
uintptr_t addr_io_coin_input;
uintptr_t addr_io_coin_input_2;
uintptr_t addr_io_coin_counter_2;
uintptr_t addr_io_game_input_stat;
uintptr_t addr_io_game_input_down;
uintptr_t addr_io_game_input_up;
uintptr_t addr_lockchip_dec_chunk;
uintptr_t addr_stop_all_effects_return;
};
const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version);
const struct exchook_mempatch_table *
exchook_mempatch_get_table(const char *version);
#endif
+63 -40
View File
@@ -10,12 +10,16 @@
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -29,7 +33,9 @@ static const struct util_options_def exchook_options_def[] = {
},
{
.name = EXCHOOK_OPTIONS_STR_GAME_VERSION,
.description = "Version of the game (format YYYYMMDD). Make sure this matches exactly the version you are"
.description =
"Version of the game (format YYYYMMDD). Make sure this matches "
"exactly the version you are"
" running because the hook lib has to apply memory patches.",
.param = 'v',
.type = UTIL_OPTIONS_TYPE_STR,
@@ -78,22 +84,26 @@ static const struct util_options_def exchook_options_def[] = {
.default_value.b = false,
},
{
.name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -144,41 +154,54 @@ static const struct util_options_defs exchook_options_defs = {
.ndefs = lengthof(exchook_options_def)
};
bool exchook_options_init(int argc, char** argv, struct exchook_options* options)
bool exchook_options_init(
int argc, char **argv, struct exchook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&exchook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&exchook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_SETTINGS);
options->game.version = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_VERSION);
options->patch.gfx.windowed = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_SETTINGS);
options->game.version =
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_VERSION);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+36 -35
View File
@@ -7,49 +7,50 @@
#include "util/log.h"
struct exchook_options {
struct game {
const char* settings;
const char* version;
} game;
struct game {
const char *settings;
const char *version;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool exchook_options_init(int argc, char** argv, struct exchook_options* options);
bool exchook_options_init(
int argc, char **argv, struct exchook_options *options);
#endif
+125 -112
View File
@@ -17,8 +17,8 @@
#include "hook/patch/hook-mon.h"
#include "hook/patch/main-loop.h"
#include "hook/patch/mounts.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -39,204 +39,217 @@ extern const uint8_t _binary_f2hook_hdd_raw_end[];
extern const uint8_t _binary_f2hook_hasp_key_start[];
extern const uint8_t _binary_f2hook_hasp_key_end[];
static void f2hook_bootstrapping(int argc, char** argv, struct f2hook_options* options, char** game_data_path)
static void f2hook_bootstrapping(
int argc,
char **argv,
struct f2hook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!f2hook_options_init(argc, argv, options)) {
exit(0);
}
if (!f2hook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_fix_locale();
hook_core_piu_utils_fix_locale();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void f2hook_patch_fs_init(struct f2hook_options* options)
static void f2hook_patch_fs_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void f2hook_fs_redir_settings(struct f2hook_options* options)
static void f2hook_fs_redir_settings(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char *abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void f2hook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void f2hook_fs_redirs_init(struct f2hook_options* options, const char* game_data_path)
static void f2hook_fs_redirs_init(
struct f2hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
f2hook_fs_redir_settings(options);
f2hook_fs_redir_settings(options);
f2hook_fs_redir_usb();
f2hook_fs_redir_usb();
}
static void f2hook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_mnt_init();
}
static void f2hook_patch_gfx_init(struct f2hook_options* options)
static void f2hook_patch_gfx_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void f2hook_patch_main_loop_init(struct f2hook_options* options)
static void f2hook_patch_main_loop_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void f2hook_patch_sound_init(struct f2hook_options* options)
static void f2hook_patch_sound_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
}
static void f2hook_patch_sigsegv_init(struct f2hook_options* options)
static void f2hook_patch_sigsegv_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void f2hook_patch_dongle_init()
{
patch_hasp_init((const uint8_t*) _binary_f2hook_hasp_key_start,
((uintptr_t) &_binary_f2hook_hasp_key_end - (uintptr_t) &_binary_f2hook_hasp_key_start));
patch_hasp_init(
(const uint8_t *) _binary_f2hook_hasp_key_start,
((uintptr_t) &_binary_f2hook_hasp_key_end -
(uintptr_t) &_binary_f2hook_hasp_key_start));
}
static void f2hook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_f2hook_hdd_raw_start,
((uintptr_t) &_binary_f2hook_hdd_raw_end - (uintptr_t) &_binary_f2hook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_f2hook_hdd_raw_start,
((uintptr_t) &_binary_f2hook_hdd_raw_end -
(uintptr_t) &_binary_f2hook_hdd_raw_start));
}
static void f2hook_patch_piuio_init(struct f2hook_options* options)
static void f2hook_patch_piuio_init(struct f2hook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
void f2hook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void f2hook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void f2hook_trap_before_main(int argc, char** argv)
void f2hook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct f2hook_options options;
char *game_data_path;
struct f2hook_options options;
f2hook_bootstrapping(argc, argv, &options, &game_data_path);
f2hook_patch_fs_init(&options);
f2hook_fs_redirs_init(&options, game_data_path);
f2hook_patch_fs_mounting_init();
f2hook_patch_gfx_init(&options);
f2hook_patch_main_loop_init(&options);
f2hook_patch_sound_init(&options);
f2hook_patch_sigsegv_init(&options);
f2hook_patch_dongle_init();
f2hook_patch_hdd_check_init();
f2hook_patch_piuio_init(&options);
f2hook_bootstrapping(argc, argv, &options, &game_data_path);
f2hook_patch_fs_init(&options);
f2hook_fs_redirs_init(&options, game_data_path);
f2hook_patch_fs_mounting_init();
f2hook_patch_gfx_init(&options);
f2hook_patch_main_loop_init(&options);
f2hook_patch_sound_init(&options);
f2hook_patch_sigsegv_init(&options);
f2hook_patch_dongle_init();
f2hook_patch_hdd_check_init();
f2hook_patch_piuio_init(&options);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void f2hook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(f2hook_constructor);
+66 -44
View File
@@ -9,14 +9,19 @@
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
"patch.net_profile.machine_id"
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -72,21 +77,24 @@ const struct util_options_def f2hook_options_def[] = {
},
{
.name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -100,7 +108,8 @@ const struct util_options_def f2hook_options_def[] = {
},
{
.name = F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -151,45 +160,58 @@ const struct util_options_defs f2hook_options_defs = {
.ndefs = lengthof(f2hook_options_def)
};
bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options)
bool f2hook_options_init(int argc, char **argv, struct f2hook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&f2hook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&f2hook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb =
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(
options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(
options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib =
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file =
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+38 -38
View File
@@ -7,53 +7,53 @@
#include "util/log.h"
struct f2hook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
uint32_t machine_id;
} net;
struct net {
const char *server;
uint32_t machine_id;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options);
bool f2hook_options_init(int argc, char **argv, struct f2hook_options *options);
#endif
+124 -111
View File
@@ -17,8 +17,8 @@
#include "hook/patch/main-loop.h"
#include "hook/patch/microdog40.h"
#include "hook/patch/mounts.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -39,202 +39,215 @@ extern const uint8_t _binary_fexhook_hdd_raw_end[];
extern const uint8_t _binary_fexhook_dog_key_start[];
extern const uint8_t _binary_fexhook_dog_key_end[];
static void fexhook_bootstrapping(int argc, char** argv, struct fexhook_options* options, char** game_data_path)
static void fexhook_bootstrapping(
int argc,
char **argv,
struct fexhook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!fexhook_options_init(argc, argv, options)) {
exit(0);
}
if (!fexhook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void fexhook_patch_fs_init(struct fexhook_options* options)
static void fexhook_patch_fs_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void fexhook_fs_redir_settings(struct fexhook_options* options)
static void fexhook_fs_redir_settings(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char *abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void fexhook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void fexhook_fs_redirs_init(struct fexhook_options* options, const char* game_data_path)
static void fexhook_fs_redirs_init(
struct fexhook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
fexhook_fs_redir_settings(options);
fexhook_fs_redir_settings(options);
fexhook_fs_redir_usb();
fexhook_fs_redir_usb();
}
static void fexhook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_mnt_init();
}
static void fexhook_patch_gfx_init(struct fexhook_options* options)
static void fexhook_patch_gfx_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void fexhook_patch_main_loop_init(struct fexhook_options* options)
static void fexhook_patch_main_loop_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void fexhook_patch_sound_init(struct fexhook_options* options)
static void fexhook_patch_sound_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
}
static void fexhook_patch_sigsegv_init(struct fexhook_options* options)
static void fexhook_patch_sigsegv_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void fexhook_patch_dongle_init()
{
patch_microdog40_init((const uint8_t*) _binary_fexhook_dog_key_start,
((uintptr_t) &_binary_fexhook_dog_key_end - (uintptr_t) &_binary_fexhook_dog_key_start));
patch_microdog40_init(
(const uint8_t *) _binary_fexhook_dog_key_start,
((uintptr_t) &_binary_fexhook_dog_key_end -
(uintptr_t) &_binary_fexhook_dog_key_start));
}
static void fexhook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_fexhook_hdd_raw_start,
((uintptr_t) &_binary_fexhook_hdd_raw_end - (uintptr_t) &_binary_fexhook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_fexhook_hdd_raw_start,
((uintptr_t) &_binary_fexhook_hdd_raw_end -
(uintptr_t) &_binary_fexhook_hdd_raw_start));
}
static void fexhook_patch_piuio_init(struct fexhook_options* options)
static void fexhook_patch_piuio_init(struct fexhook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
void fexhook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void fexhook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void fexhook_trap_before_main(int argc, char** argv)
void fexhook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct fexhook_options options;
char *game_data_path;
struct fexhook_options options;
fexhook_bootstrapping(argc, argv, &options, &game_data_path);
fexhook_patch_fs_init(&options);
fexhook_fs_redirs_init(&options, game_data_path);
fexhook_patch_fs_mounting_init();
fexhook_patch_gfx_init(&options);
fexhook_patch_main_loop_init(&options);
fexhook_patch_sound_init(&options);
fexhook_patch_sigsegv_init(&options);
fexhook_patch_dongle_init();
fexhook_patch_hdd_check_init();
fexhook_patch_piuio_init(&options);
fexhook_bootstrapping(argc, argv, &options, &game_data_path);
fexhook_patch_fs_init(&options);
fexhook_fs_redirs_init(&options, game_data_path);
fexhook_patch_fs_mounting_init();
fexhook_patch_gfx_init(&options);
fexhook_patch_main_loop_init(&options);
fexhook_patch_sound_init(&options);
fexhook_patch_sigsegv_init(&options);
fexhook_patch_dongle_init();
fexhook_patch_hdd_check_init();
fexhook_patch_piuio_init(&options);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void fexhook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(fexhook_constructor);
+69 -45
View File
@@ -9,14 +9,19 @@
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
"patch.net_profile.machine_id"
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -71,22 +76,26 @@ const struct util_options_def fexhook_options_def[] = {
.default_value.b = false,
},
{
.name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -100,7 +109,8 @@ const struct util_options_def fexhook_options_def[] = {
},
{
.name = FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -151,45 +161,59 @@ const struct util_options_defs fexhook_options_defs = {
.ndefs = lengthof(fexhook_options_def)
};
bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options)
bool fexhook_options_init(
int argc, char **argv, struct fexhook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&fexhook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&fexhook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+39 -38
View File
@@ -7,53 +7,54 @@
#include "util/log.h"
struct fexhook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
uint32_t machine_id;
} net;
struct net {
const char *server;
uint32_t machine_id;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options);
bool fexhook_options_init(
int argc, char **argv, struct fexhook_options *options);
#endif
+124 -111
View File
@@ -17,8 +17,8 @@
#include "hook/patch/main-loop.h"
#include "hook/patch/microdog40.h"
#include "hook/patch/mounts.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -39,202 +39,215 @@ extern const uint8_t _binary_fsthook_hdd_raw_end[];
extern const uint8_t _binary_fsthook_dog_key_start[];
extern const uint8_t _binary_fsthook_dog_key_end[];
static void fsthook_bootstrapping(int argc, char** argv, struct fsthook_options* options, char** game_data_path)
static void fsthook_bootstrapping(
int argc,
char **argv,
struct fsthook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!fsthook_options_init(argc, argv, options)) {
exit(0);
}
if (!fsthook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void fsthook_patch_fs_init(struct fsthook_options* options)
static void fsthook_patch_fs_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void fsthook_fs_redir_settings(struct fsthook_options* options)
static void fsthook_fs_redir_settings(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char *abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void fsthook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void fsthook_fs_redirs_init(struct fsthook_options* options, const char* game_data_path)
static void fsthook_fs_redirs_init(
struct fsthook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
fsthook_fs_redir_settings(options);
fsthook_fs_redir_settings(options);
fsthook_fs_redir_usb();
fsthook_fs_redir_usb();
}
static void fsthook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_mnt_init();
}
static void fsthook_patch_gfx_init(struct fsthook_options* options)
static void fsthook_patch_gfx_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void fsthook_patch_main_loop_init(struct fsthook_options* options)
static void fsthook_patch_main_loop_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void fsthook_patch_sound_init(struct fsthook_options* options)
static void fsthook_patch_sound_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
}
static void fsthook_patch_sigsegv_init(struct fsthook_options* options)
static void fsthook_patch_sigsegv_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void fsthook_patch_dongle_init()
{
patch_microdog40_init((const uint8_t*) _binary_fsthook_dog_key_start,
((uintptr_t) &_binary_fsthook_dog_key_end - (uintptr_t) &_binary_fsthook_dog_key_start));
patch_microdog40_init(
(const uint8_t *) _binary_fsthook_dog_key_start,
((uintptr_t) &_binary_fsthook_dog_key_end -
(uintptr_t) &_binary_fsthook_dog_key_start));
}
static void fsthook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_fsthook_hdd_raw_start,
((uintptr_t) &_binary_fsthook_hdd_raw_end - (uintptr_t) &_binary_fsthook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_fsthook_hdd_raw_start,
((uintptr_t) &_binary_fsthook_hdd_raw_end -
(uintptr_t) &_binary_fsthook_hdd_raw_start));
}
static void fsthook_patch_piuio_init(struct fsthook_options* options)
static void fsthook_patch_piuio_init(struct fsthook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
void fsthook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void fsthook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void fsthook_trap_before_main(int argc, char** argv)
void fsthook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct fsthook_options options;
char *game_data_path;
struct fsthook_options options;
fsthook_bootstrapping(argc, argv, &options, &game_data_path);
fsthook_patch_fs_init(&options);
fsthook_fs_redirs_init(&options, game_data_path);
fsthook_patch_fs_mounting_init();
fsthook_patch_gfx_init(&options);
fsthook_patch_main_loop_init(&options);
fsthook_patch_sound_init(&options);
fsthook_patch_sigsegv_init(&options);
fsthook_patch_dongle_init();
fsthook_patch_hdd_check_init();
fsthook_patch_piuio_init(&options);
fsthook_bootstrapping(argc, argv, &options, &game_data_path);
fsthook_patch_fs_init(&options);
fsthook_fs_redirs_init(&options, game_data_path);
fsthook_patch_fs_mounting_init();
fsthook_patch_gfx_init(&options);
fsthook_patch_main_loop_init(&options);
fsthook_patch_sound_init(&options);
fsthook_patch_sigsegv_init(&options);
fsthook_patch_dongle_init();
fsthook_patch_hdd_check_init();
fsthook_patch_piuio_init(&options);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void fsthook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(fsthook_constructor);
+70 -46
View File
@@ -9,14 +9,19 @@
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
"patch.net_profile.machine_id"
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -26,7 +31,7 @@ const struct util_options_def fsthook_options_def[] = {
.description = "Path to game settings (SETTINGS) folder",
.param = 's',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = "./save",
.default_value.str = "./save",
},
{
.name = FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED,
@@ -71,22 +76,26 @@ const struct util_options_def fsthook_options_def[] = {
.default_value.b = false,
},
{
.name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -100,7 +109,8 @@ const struct util_options_def fsthook_options_def[] = {
},
{
.name = FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -151,45 +161,59 @@ const struct util_options_defs fsthook_options_defs = {
.ndefs = lengthof(fsthook_options_def)
};
bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options)
bool fsthook_options_init(
int argc, char **argv, struct fsthook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&fsthook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&fsthook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+39 -38
View File
@@ -7,53 +7,54 @@
#include "util/log.h"
struct fsthook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
uint32_t machine_id;
} net;
struct net {
const char *server;
uint32_t machine_id;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options);
bool fsthook_options_init(
int argc, char **argv, struct fsthook_options *options);
#endif
+26 -19
View File
@@ -10,32 +10,39 @@
typedef int (*cnh_fshook_chdir_t)(const char *path);
static cnh_fshook_chdir_t mk3hook_1st_2nd_fs_fix_real_chdir;
static char* mk3hook_1st_2nd_fs_fix_path_game_dir_abs;
static char *mk3hook_1st_2nd_fs_fix_path_game_dir_abs;
int chdir(const char *path)
{
if (!mk3hook_1st_2nd_fs_fix_real_chdir) {
mk3hook_1st_2nd_fs_fix_real_chdir = (cnh_fshook_chdir_t) cnh_lib_get_func_addr("chdir");
}
if (!mk3hook_1st_2nd_fs_fix_real_chdir) {
mk3hook_1st_2nd_fs_fix_real_chdir =
(cnh_fshook_chdir_t) cnh_lib_get_func_addr("chdir");
}
// This seems to be some kind of probe the game is doing to determine something...I assume which folder layout to
// use? When we change directory to our "game" dir which contains all stuff at that point, everything's fine.
// If we do not do that, the game will error not being able to find any files. When loading files, the code also
// does some odd iterating the file system starting at / at that point. I assume that this is some sort of search
// trying to look for the file on the filesystem. However, that breaks a lot of other stuf with the hooking code
// and therefore should not be triggered.
if (mk3hook_1st_2nd_fs_fix_path_game_dir_abs && !strcmp(path, "/datas/bga")) {
log_debug("Trapping /datas/bga chdir, chdir to %s", mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
// This seems to be some kind of probe the game is doing to determine
// something...I assume which folder layout to use? When we change directory
// to our "game" dir which contains all stuff at that point, everything's
// fine. If we do not do that, the game will error not being able to find any
// files. When loading files, the code also does some odd iterating the file
// system starting at / at that point. I assume that this is some sort of
// search trying to look for the file on the filesystem. However, that breaks
// a lot of other stuf with the hooking code and therefore should not be
// triggered.
if (mk3hook_1st_2nd_fs_fix_path_game_dir_abs && !strcmp(path, "/datas/bga")) {
log_debug(
"Trapping /datas/bga chdir, chdir to %s",
mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
return mk3hook_1st_2nd_fs_fix_real_chdir(mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
} else {
return mk3hook_1st_2nd_fs_fix_real_chdir(path);
}
return mk3hook_1st_2nd_fs_fix_real_chdir(
mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
} else {
return mk3hook_1st_2nd_fs_fix_real_chdir(path);
}
}
void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs)
void mk3hook_1st_2nd_fs_fix_init(const char *path_game_dir_abs)
{
mk3hook_1st_2nd_fs_fix_path_game_dir_abs = util_str_dup(path_game_dir_abs);
mk3hook_1st_2nd_fs_fix_path_game_dir_abs = util_str_dup(path_game_dir_abs);
log_info("Initialized");
log_info("Initialized");
}
+5 -3
View File
@@ -1,5 +1,6 @@
/**
* Fixes an issue with the engine of 1st and 2nd when redirecting all game data to one game folder, e.g. ./game/.
* Fixes an issue with the engine of 1st and 2nd when redirecting all game data
* to one game folder, e.g. ./game/.
*/
#ifndef MK3HOOK_1ST_2ND_FS_FIX_H
#define MK3HOOK_1ST_2ND_FS_FIX_H
@@ -7,8 +8,9 @@
/**
* Initialize the module.
*
* @param path_game_dir_abs The absolute path to the "game" dir containing all game assets.
* @param path_game_dir_abs The absolute path to the "game" dir containing all
* game assets.
*/
void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs);
void mk3hook_1st_2nd_fs_fix_init(const char *path_game_dir_abs);
#endif
+85 -78
View File
@@ -14,123 +14,130 @@ static double mk3hook_config_music_volume;
static double mk3hook_config_sfx_volume;
static int mk3hook_config_fullscreen;
static int mk3hook_config_allow_exit;
static const char* mk3hook_config_save_file;
static const char *mk3hook_config_save_file;
int config_read_file(config_t *config, const char *filename)
{
// Just stub file loading
log_debug("config_read_file: %s", filename);
// Just stub file loading
log_debug("config_read_file: %s", filename);
return 1;
return 1;
}
int config_lookup_int(const config_t *config, const char *path, int *value)
{
log_debug("config_lookup_int: %s", path);
log_debug("config_lookup_int: %s", path);
if (!strcmp(path, "sync_offset")) {
*value = mk3hook_config_sync_offset;
} else {
log_error("Unsupported int entry read: %s", path);
}
if (!strcmp(path, "sync_offset")) {
*value = mk3hook_config_sync_offset;
} else {
log_error("Unsupported int entry read: %s", path);
}
return 1;
return 1;
}
int config_lookup_float(const config_t *config, const char *path, double *value)
{
log_debug("config_lookup_float: %s", path);
log_debug("config_lookup_float: %s", path);
if (!strcmp(path, "sync_multiplier")) {
*value = mk3hook_config_sync_multiplier;
} else if (!strcmp(path, "music_volume")) {
*value = mk3hook_config_music_volume;
} else if (!strcmp(path, "sfx_volume")) {
*value = mk3hook_config_sfx_volume;
} else {
log_error("Unsupported float entry read: %s", path);
}
if (!strcmp(path, "sync_multiplier")) {
*value = mk3hook_config_sync_multiplier;
} else if (!strcmp(path, "music_volume")) {
*value = mk3hook_config_music_volume;
} else if (!strcmp(path, "sfx_volume")) {
*value = mk3hook_config_sfx_volume;
} else {
log_error("Unsupported float entry read: %s", path);
}
return 1;
return 1;
}
int config_lookup_bool(const config_t *config, const char *path, int *value)
{
log_debug("config_lookup_bool: %s", path);
log_debug("config_lookup_bool: %s", path);
if (!strcmp(path, "fullscreen")) {
*value = mk3hook_config_fullscreen;
} else if (!strcmp(path, "allow_exit")) {
*value = mk3hook_config_allow_exit;
} else {
log_error("Unsupported bool entry read: %s", path);
}
if (!strcmp(path, "fullscreen")) {
*value = mk3hook_config_fullscreen;
} else if (!strcmp(path, "allow_exit")) {
*value = mk3hook_config_allow_exit;
} else {
log_error("Unsupported bool entry read: %s", path);
}
return 1;
return 1;
}
int config_lookup_string(const config_t *config, const char *path, const char **value)
int config_lookup_string(
const config_t *config, const char *path, const char **value)
{
log_debug("config_lookup_string: %s", path);
log_debug("config_lookup_string: %s", path);
if (!strcmp(path, "save_file")) {
// Note: This is fine as the size of the string pointed to by the returned address is not relevant for any
// operations using them, e.g. there is no merging/copying with limited stack'd buffer sizes involved like
// below.
*value = mk3hook_config_save_file;
} else if (!strcmp(path, "effect_path")) {
// Needs to be hardcoded because the stack buffer for this is only 128 bytes large. This is likely fine for most
// paths and even when resolving relative paths to absolute ones. Still, this is a risk for a buffer overflow.
// Utilize the redirect module in the main lib hook function to redirect this to something like a local game dir
// and resolve this to an absolute path
*value = "EFFECTS/";
} else if (!strcmp(path, "track_path")) {
// Needs to be hardcoded because the stack buffer for this is only 32 bytes large. When combining it with the
// "Track%02i.mp3" part, the buffer will overflow when this path is longer or even resolved to an absolute path.
// Utilize the redirect module in the main lib hook function to redirect this to something like a local game dir
// and resolve this to an absolute path
*value = "track/";
} else {
log_error("Unsupported string entry read: %s", path);
}
if (!strcmp(path, "save_file")) {
// Note: This is fine as the size of the string pointed to by the returned
// address is not relevant for any operations using them, e.g. there is no
// merging/copying with limited stack'd buffer sizes involved like below.
*value = mk3hook_config_save_file;
} else if (!strcmp(path, "effect_path")) {
// Needs to be hardcoded because the stack buffer for this is only 128 bytes
// large. This is likely fine for most paths and even when resolving
// relative paths to absolute ones. Still, this is a risk for a buffer
// overflow. Utilize the redirect module in the main lib hook function to
// redirect this to something like a local game dir and resolve this to an
// absolute path
*value = "EFFECTS/";
} else if (!strcmp(path, "track_path")) {
// Needs to be hardcoded because the stack buffer for this is only 32 bytes
// large. When combining it with the "Track%02i.mp3" part, the buffer will
// overflow when this path is longer or even resolved to an absolute path.
// Utilize the redirect module in the main lib hook function to redirect
// this to something like a local game dir and resolve this to an absolute
// path
*value = "track/";
} else {
log_error("Unsupported string entry read: %s", path);
}
return 1;
return 1;
}
static void mk3hook_config_assign_save_file(const struct mk3hook_options* options)
static void
mk3hook_config_assign_save_file(const struct mk3hook_options *options)
{
const char* folder = options->game.settings;
const char *folder = options->game.settings;
if (!util_fs_path_exists(folder)) {
log_info("Settings path %s does not exist, creating", folder);
if (!util_fs_path_exists(folder)) {
log_info("Settings path %s does not exist, creating", folder);
if (!util_fs_mkdir(folder)) {
log_error("Creating directory %s failed", folder);
}
if (!util_fs_mkdir(folder)) {
log_error("Creating directory %s failed", folder);
}
}
char* folder_abs = util_fs_get_abs_path(folder);
char *folder_abs = util_fs_get_abs_path(folder);
if (!folder_abs) {
log_error("Failed to resolve absolute path for settings folder");
return;
}
if (!folder_abs) {
log_error("Failed to resolve absolute path for settings folder");
return;
}
// Don't free this one after assigning the result value as this will still be read from. Keep memory leak.
mk3hook_config_save_file = util_str_merge(folder_abs, "/EEPROM.BIN");
free(folder_abs);
// Don't free this one after assigning the result value as this will still be
// read from. Keep memory leak.
mk3hook_config_save_file = util_str_merge(folder_abs, "/EEPROM.BIN");
free(folder_abs);
}
void mk3hook_config_init(const struct mk3hook_options* options)
void mk3hook_config_init(const struct mk3hook_options *options)
{
mk3hook_config_sync_offset = options->game.sync_offset;
mk3hook_config_sync_multiplier = options->game.sync_multiplier;
mk3hook_config_music_volume = options->game.music_vol;
mk3hook_config_sfx_volume = options->game.sfx_vol;
mk3hook_config_fullscreen = !options->patch.gfx.windowed;
mk3hook_config_allow_exit = options->patch.piuio.exit_test_serv;
mk3hook_config_sync_offset = options->game.sync_offset;
mk3hook_config_sync_multiplier = options->game.sync_multiplier;
mk3hook_config_music_volume = options->game.music_vol;
mk3hook_config_sfx_volume = options->game.sfx_vol;
mk3hook_config_fullscreen = !options->patch.gfx.windowed;
mk3hook_config_allow_exit = options->patch.piuio.exit_test_serv;
mk3hook_config_assign_save_file(options);
mk3hook_config_assign_save_file(options);
log_info("Initialized");
log_info("Initialized");
}
+5 -4
View File
@@ -1,6 +1,6 @@
/**
* Patch the configuration file handling which uses libconfig. This hooks libconfig up to pumptools configuration
* infrastructure.
* Patch the configuration file handling which uses libconfig. This hooks
* libconfig up to pumptools configuration infrastructure.
*/
#ifndef MK3HOOK_CONFIG_H
#define MK3HOOK_CONFIG_H
@@ -10,8 +10,9 @@
/**
* Initialize this module.
*
* @param options The options provided to the hook which are injected into libconfig config value reading.
* @param options The options provided to the hook which are injected into
* libconfig config value reading.
*/
void mk3hook_config_init(const struct mk3hook_options* options);
void mk3hook_config_init(const struct mk3hook_options *options);
#endif
+125 -81
View File
@@ -10,117 +10,161 @@
#include "util/log.h"
#include "util/str.h"
typedef FMOD_RESULT (*FMOD_System_Init_t)(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata);
typedef FMOD_RESULT (*FMOD_System_Init_t)(
FMOD_SYSTEM *system,
int maxchannels,
FMOD_INITFLAGS flags,
void *extradriverdata);
static FMOD_System_Init_t mk3hook_fmodex_real_FMOD_System_Init;
static bool mk3hook_fmodex_debug_output;
static const char* mk3hook_fmodex_sound_device;
static const char *mk3hook_fmodex_sound_device;
FMOD_RESULT FMOD_System_Init(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata)
FMOD_RESULT FMOD_System_Init(
FMOD_SYSTEM *system,
int maxchannels,
FMOD_INITFLAGS flags,
void *extradriverdata)
{
if (!mk3hook_fmodex_real_FMOD_System_Init) {
mk3hook_fmodex_real_FMOD_System_Init = (FMOD_System_Init_t) cnh_lib_get_func_addr("FMOD_System_Init");
}
if (!mk3hook_fmodex_real_FMOD_System_Init) {
mk3hook_fmodex_real_FMOD_System_Init =
(FMOD_System_Init_t) cnh_lib_get_func_addr("FMOD_System_Init");
}
FMOD_RESULT res;
FMOD_RESULT res;
unsigned int version;
unsigned int version;
res = FMOD_System_GetVersion(system, &version);
res = FMOD_System_GetVersion(system, &version);
if (res != FMOD_OK) {
log_error(
"FMOD_System_GetVersion failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
log_info(
"fmodex version: %d.%d.%d",
(version >> 16) & 0xFFFF,
(version >> 8) & 0xFF,
version & 0xFF);
if (mk3hook_fmodex_debug_output) {
res = FMOD_Debug_SetLevel(FMOD_DEBUG_ALL);
if (res != FMOD_OK) {
log_error("FMOD_System_GetVersion failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
log_error(
"FMOD_Debug_SetLevel failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
}
log_info("fmodex version: %d.%d.%d", (version >> 16) & 0xFFFF, (version >> 8) & 0xFF, version & 0xFF);
res = FMOD_System_SetOutput(system, FMOD_OUTPUTTYPE_ALSA);
if (mk3hook_fmodex_debug_output) {
res = FMOD_Debug_SetLevel(FMOD_DEBUG_ALL);
if (res != FMOD_OK) {
log_error(
"FMOD_System_SetOutput failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
if (res != FMOD_OK) {
log_error("FMOD_Debug_SetLevel failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
}
FMOD_OUTPUTTYPE output_type;
res = FMOD_System_SetOutput(system, FMOD_OUTPUTTYPE_ALSA);
res = FMOD_System_GetOutput(system, &output_type);
if (res != FMOD_OK) {
log_error(
"FMOD_System_GetOutput failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
log_info("Output type: %d", output_type);
int num_drivers;
res = FMOD_System_GetNumDrivers(system, &num_drivers);
if (res != FMOD_OK) {
log_error(
"FMOD_System_GetNumDrivers failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
log_info("Num available drivers %d", num_drivers);
char buffer[4096];
FMOD_GUID guid;
int selected_driver = -1;
for (int i = 0; i < num_drivers; i++) {
res = FMOD_System_GetDriverInfo(system, i, buffer, sizeof(buffer), &guid);
if (res != FMOD_OK) {
log_error("FMOD_System_SetOutput failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
log_error(
"FMOD_System_GetDriverInfo failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
break;
}
FMOD_OUTPUTTYPE output_type;
log_info("Driver %d: %s", i, buffer);
res = FMOD_System_GetOutput(system, &output_type);
if (res != FMOD_OK) {
log_error("FMOD_System_GetOutput failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
if (mk3hook_fmodex_sound_device &&
!strcmp(buffer, mk3hook_fmodex_sound_device)) {
selected_driver = i;
}
}
log_info("Output type: %d", output_type);
if (selected_driver == -1) {
log_info(
"Selecting default driver (0) because either the selected driver was "
"not found or no driver was "
"selected");
selected_driver = 0;
} else {
log_info(
"Found selected driver %s, id %d",
mk3hook_fmodex_sound_device,
selected_driver);
}
int num_drivers;
res = FMOD_System_GetNumDrivers(system, &num_drivers);
res = FMOD_System_SetDriver(system, selected_driver);
if (res != FMOD_OK) {
log_error("FMOD_System_GetNumDrivers failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
if (res != FMOD_OK) {
log_error(
"FMOD_System_SetDriver failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
log_info("Num available drivers %d", num_drivers);
res = FMOD_System_SetSpeakerMode(system, FMOD_SPEAKERMODE_STEREO);
char buffer[4096];
FMOD_GUID guid;
int selected_driver = -1;
if (res != FMOD_OK) {
log_error(
"FMOD_System_SetSpeakerMode failed %d: %s",
res,
FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
for (int i = 0; i < num_drivers; i++) {
res = FMOD_System_GetDriverInfo(system, i, buffer, sizeof(buffer), &guid);
if (res != FMOD_OK) {
log_error("FMOD_System_GetDriverInfo failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
break;
}
log_info("Driver %d: %s", i, buffer);
if (mk3hook_fmodex_sound_device && !strcmp(buffer, mk3hook_fmodex_sound_device)) {
selected_driver = i;
}
}
if (selected_driver == -1) {
log_info("Selecting default driver (0) because either the selected driver was not found or no driver was "
"selected");
selected_driver = 0;
} else {
log_info("Found selected driver %s, id %d", mk3hook_fmodex_sound_device, selected_driver);
}
res = FMOD_System_SetDriver(system, selected_driver);
if (res != FMOD_OK) {
log_error("FMOD_System_SetDriver failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
res = FMOD_System_SetSpeakerMode(system, FMOD_SPEAKERMODE_STEREO);
if (res != FMOD_OK) {
log_error("FMOD_System_SetSpeakerMode failed %d: %s", res, FMOD_ErrorString((FMOD_RESULT) res));
return res;
}
return mk3hook_fmodex_real_FMOD_System_Init(system, maxchannels, flags, extradriverdata);
return mk3hook_fmodex_real_FMOD_System_Init(
system, maxchannels, flags, extradriverdata);
}
void mk3hook_fmodex_init(bool debug_output, const char* sound_device)
void mk3hook_fmodex_init(bool debug_output, const char *sound_device)
{
mk3hook_fmodex_debug_output = debug_output;
mk3hook_fmodex_sound_device = sound_device;
mk3hook_fmodex_debug_output = debug_output;
mk3hook_fmodex_sound_device = sound_device;
log_info("Initialized");
log_info("Initialized");
}
+8 -6
View File
@@ -1,6 +1,6 @@
/**
* This patch module fixes a bunch of issues with fmodex which is used by the MK3 Linux ports to re-implement
* the sound hardware in software.
* This patch module fixes a bunch of issues with fmodex which is used by the
* MK3 Linux ports to re-implement the sound hardware in software.
*/
#ifndef MK3HOOK_FMODEX_H
#define MK3HOOK_FMODEX_H
@@ -10,10 +10,12 @@
/**
* Initialize this patch module.
*
* @param debug_output True to enable fmodex's debug output which requires the usage of fmodexL.so instead of fmodex.so.
* @param sound_device Provide a sound device to pick from the list of devices available with fmodex. NULL to go with
* with default device selected automatically by fmodex.
* @param debug_output True to enable fmodex's debug output which requires the
* usage of fmodexL.so instead of fmodex.so.
* @param sound_device Provide a sound device to pick from the list of devices
* available with fmodex. NULL to go with with default device selected
* automatically by fmodex.
*/
void mk3hook_fmodex_init(bool debug_output, const char* sound_device);
void mk3hook_fmodex_init(bool debug_output, const char *sound_device);
#endif
+149 -136
View File
@@ -16,8 +16,8 @@
#include "hook/patch/asound-fix.h"
#include "hook/patch/hook-mon.h"
#include "hook/patch/main-loop.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -31,219 +31,232 @@
#include "util/str.h"
#include "util/sys-info.h"
static void mk3hook_bootstrapping(int argc, char** argv, struct mk3hook_options* options, char** game_data_path)
static void mk3hook_bootstrapping(
int argc,
char **argv,
struct mk3hook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (!mk3hook_options_init(argc, argv, options)) {
exit(0);
}
if (!mk3hook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
// Have different arguments to align with newer pump games
// argv[1]: game folder path
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
// Have different arguments to align with newer pump games
// argv[1]: game folder path
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void mk3hook_patch_config_init(struct mk3hook_options* options)
static void mk3hook_patch_config_init(struct mk3hook_options *options)
{
mk3hook_config_init(options);
mk3hook_config_init(options);
}
static void mk3hook_patch_fs_init(struct mk3hook_options* options)
static void mk3hook_patch_fs_init(struct mk3hook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void mk3hook_1st_2nd_fs_redirs(const char* game_data_path_abs)
static void mk3hook_1st_2nd_fs_redirs(const char *game_data_path_abs)
{
log_assert(game_data_path_abs);
log_assert(game_data_path_abs);
// The "datas" directory does not require a redirect as the game uses chdir to move to that folder. For this, the
// additional patch module "1st-2nd-fs-fix" is required (see below). All files usually local to the piu executable,
// which are outside of the "datas" folder, have to be redirected.
cnh_redir_add("INTRO.ANI", util_str_merge(game_data_path_abs, "/INTRO.ANI"));
cnh_redir_add("intro.ani", util_str_merge(game_data_path_abs, "/INTRO.ANI"));
cnh_redir_add("spr.res", util_str_merge(game_data_path_abs, "/SPR.RES"));
cnh_redir_add("SPR.RES", util_str_merge(game_data_path_abs, "/SPR.RES"));
cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
// The "datas" directory does not require a redirect as the game uses chdir to
// move to that folder. For this, the additional patch module "1st-2nd-fs-fix"
// is required (see below). All files usually local to the piu executable,
// which are outside of the "datas" folder, have to be redirected.
cnh_redir_add("INTRO.ANI", util_str_merge(game_data_path_abs, "/INTRO.ANI"));
cnh_redir_add("intro.ani", util_str_merge(game_data_path_abs, "/INTRO.ANI"));
cnh_redir_add("spr.res", util_str_merge(game_data_path_abs, "/SPR.RES"));
cnh_redir_add("SPR.RES", util_str_merge(game_data_path_abs, "/SPR.RES"));
cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
// For redirecting additional files for linux ports. Configurable via MK3 linux ports config.cfg but causes stack
// overflow on long paths. Redirecting the paths afterwards is save.
cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/"));
cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/"));
// For redirecting additional files for linux ports. Configurable via MK3
// linux ports config.cfg but causes stack overflow on long paths. Redirecting
// the paths afterwards is save.
cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/"));
cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/"));
mk3hook_1st_2nd_fs_fix_init(game_data_path_abs);
mk3hook_1st_2nd_fs_fix_init(game_data_path_abs);
}
static void mk3hook_3rd_and_up_fs_redirs(const char* game_data_path_abs)
static void mk3hook_3rd_and_up_fs_redirs(const char *game_data_path_abs)
{
log_assert(game_data_path_abs);
log_assert(game_data_path_abs);
// Sometimes, the game decides to read stuff using lower case, sometimes upper case *shrug*
// Also, we don't are about cleaning up the resulting merged strings here. Have some memory leaks!
cnh_redir_add(".", util_str_merge(game_data_path_abs, "/"));
cnh_redir_add("audio", util_str_merge(game_data_path_abs, "/AUDIO"));
cnh_redir_add("AUDIO", util_str_merge(game_data_path_abs, "/AUDIO"));
cnh_redir_add("bga", util_str_merge(game_data_path_abs, "/BGA"));
cnh_redir_add("BGA", util_str_merge(game_data_path_abs, "/BGA"));
cnh_redir_add("step", util_str_merge(game_data_path_abs, "/STEP"));
cnh_redir_add("STEP", util_str_merge(game_data_path_abs, "/STEP"));
cnh_redir_add("title", util_str_merge(game_data_path_abs, "/TITLE"));
cnh_redir_add("TITLE", util_str_merge(game_data_path_abs, "/TITLE"));
cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
// Special treatment for extra because keeping the name stage.cfg was not good enough...
cnh_redir_add("game.cfg", util_str_merge(game_data_path_abs, "/GAME.CFG"));
cnh_redir_add("GAME.CFG", util_str_merge(game_data_path_abs, "/GAME.CFG"));
// Sometimes, the game decides to read stuff using lower case, sometimes upper
// case *shrug* Also, we don't are about cleaning up the resulting merged
// strings here. Have some memory leaks!
cnh_redir_add(".", util_str_merge(game_data_path_abs, "/"));
cnh_redir_add("audio", util_str_merge(game_data_path_abs, "/AUDIO"));
cnh_redir_add("AUDIO", util_str_merge(game_data_path_abs, "/AUDIO"));
cnh_redir_add("bga", util_str_merge(game_data_path_abs, "/BGA"));
cnh_redir_add("BGA", util_str_merge(game_data_path_abs, "/BGA"));
cnh_redir_add("step", util_str_merge(game_data_path_abs, "/STEP"));
cnh_redir_add("STEP", util_str_merge(game_data_path_abs, "/STEP"));
cnh_redir_add("title", util_str_merge(game_data_path_abs, "/TITLE"));
cnh_redir_add("TITLE", util_str_merge(game_data_path_abs, "/TITLE"));
cnh_redir_add("piu.bin", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("PIU.BIN", util_str_merge(game_data_path_abs, "/PIU.BIN"));
cnh_redir_add("stage.cfg", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
cnh_redir_add("STAGE.CFG", util_str_merge(game_data_path_abs, "/STAGE.CFG"));
// Special treatment for extra because keeping the name stage.cfg was not good
// enough...
cnh_redir_add("game.cfg", util_str_merge(game_data_path_abs, "/GAME.CFG"));
cnh_redir_add("GAME.CFG", util_str_merge(game_data_path_abs, "/GAME.CFG"));
// For redirecting additional files for linux ports. Configurable via MK3 linux ports config.cfg but causes stack
// overflow on long paths. Redirecting the paths afterwards is save.
cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/"));
cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/"));
// For redirecting additional files for linux ports. Configurable via MK3
// linux ports config.cfg but causes stack overflow on long paths. Redirecting
// the paths afterwards is save.
cnh_redir_add("EFFECTS", util_str_merge(game_data_path_abs, "/EFFECTS/"));
cnh_redir_add("track", util_str_merge(game_data_path_abs, "/track/"));
}
static void mk3hook_patch_1st_and_2nd_fs_init(struct mk3hook_options* options, const char* game_data_path)
static void mk3hook_patch_1st_and_2nd_fs_init(
struct mk3hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
char* game_data_path_abs = util_fs_get_abs_path(game_data_path);
char *game_data_path_abs = util_fs_get_abs_path(game_data_path);
if (options->game.fs_1st_2nd) {
mk3hook_1st_2nd_fs_redirs(game_data_path_abs);
} else {
mk3hook_3rd_and_up_fs_redirs(game_data_path_abs);
}
if (options->game.fs_1st_2nd) {
mk3hook_1st_2nd_fs_redirs(game_data_path_abs);
} else {
mk3hook_3rd_and_up_fs_redirs(game_data_path_abs);
}
free(game_data_path_abs);
free(game_data_path_abs);
}
static void mk3hook_patch_main_loop_init(struct mk3hook_options* options)
static void mk3hook_patch_main_loop_init(struct mk3hook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, true);
patch_main_loop_init(
true, options->patch.main_loop.disable_built_in_inputs, true);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void mk3hook_patch_sound_init(struct mk3hook_options* options)
static void mk3hook_patch_sound_init(struct mk3hook_options *options)
{
log_assert(options);
log_assert(options);
patch_asound_fix_init();
mk3hook_fmodex_init(options->patch.sound.debug_output, options->patch.sound.device);
patch_asound_fix_init();
mk3hook_fmodex_init(
options->patch.sound.debug_output, options->patch.sound.device);
}
static void mk3hook_patch_sigsegv_init(struct mk3hook_options* options)
static void mk3hook_patch_sigsegv_init(struct mk3hook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void mk3hook_patch_piuio_init(struct mk3hook_options* options)
static void mk3hook_patch_piuio_init(struct mk3hook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_emu_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
static void mk3hook_fix_argv(int argc, char** argv)
static void mk3hook_fix_argv(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
// Game exec main expects the following arguments
// argv[1]: cfg1 path
// argv[2]: cfg2 path (optional)
// Config loading is stubbed, so just provide something
// Game exec main expects the following arguments
// argv[1]: cfg1 path
// argv[2]: cfg2 path (optional)
// Config loading is stubbed, so just provide something
argv[1] = "./save/config.cfg";
argv[1] = "./save/config.cfg";
if (argc > 2) {
argv[2] = "./save/config.cfg";
}
if (argc > 2) {
argv[2] = "./save/config.cfg";
}
}
void mk3hook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void mk3hook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void mk3hook_trap_before_main(int argc, char** argv)
void mk3hook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
struct mk3hook_options options;
char* game_data_path;
struct mk3hook_options options;
char *game_data_path;
mk3hook_bootstrapping(argc, argv, &options, &game_data_path);
mk3hook_patch_config_init(&options);
mk3hook_patch_fs_init(&options);
mk3hook_patch_1st_and_2nd_fs_init(&options, game_data_path);
mk3hook_patch_main_loop_init(&options);
mk3hook_patch_sound_init(&options);
mk3hook_patch_sigsegv_init(&options);
mk3hook_patch_piuio_init(&options);
mk3hook_fix_argv(argc, argv);
mk3hook_bootstrapping(argc, argv, &options, &game_data_path);
mk3hook_patch_config_init(&options);
mk3hook_patch_fs_init(&options);
mk3hook_patch_1st_and_2nd_fs_init(&options, game_data_path);
mk3hook_patch_main_loop_init(&options);
mk3hook_patch_sound_init(&options);
mk3hook_patch_sigsegv_init(&options);
mk3hook_patch_piuio_init(&options);
mk3hook_fix_argv(argc, argv);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void mk3hook_trap_after_main(void)
{
}
LIB_MAIN_CONSTRUCTOR(mk3hook_constructor);
+22 -18
View File
@@ -2,10 +2,12 @@
* Module to fix weird OpenGL error that only appears on all MK3 linux ports.
*
* If OpenGL is not forced into single threaded mode, the backend will run in
* multi-threaded mode for some reason and crash in __glDispatchCheckMultithreaded
* when the game calls glXChooseVisual in its GFX init function.
* multi-threaded mode for some reason and crash in
* __glDispatchCheckMultithreaded when the game calls glXChooseVisual in its GFX
* init function.
*
* The fix is quite simple (luckily) by just setting the environment variable __GL_SINGLETHREADED.
* The fix is quite simple (luckily) by just setting the environment variable
* __GL_SINGLETHREADED.
*/
#include <stdio.h>
@@ -13,25 +15,27 @@
#include "capnhook/hook/lib.h"
typedef char* (*getenv_t) (const char* name);
typedef char *(*getenv_t)(const char *name);
static getenv_t _mk3hook_ogl_fix_real_getenv;
char* getenv(const char* name)
char *getenv(const char *name)
{
if (!_mk3hook_ogl_fix_real_getenv) {
_mk3hook_ogl_fix_real_getenv = (getenv_t) cnh_lib_get_func_addr("getenv");
if (!_mk3hook_ogl_fix_real_getenv) {
_mk3hook_ogl_fix_real_getenv = (getenv_t) cnh_lib_get_func_addr("getenv");
}
char *ret = _mk3hook_ogl_fix_real_getenv(name);
if (!strcmp(name, "__GL_SINGLETHREADED")) {
if (ret == NULL || strcmp(name, "1") != 0) {
printf(
"!!! mk3hook: __GL_SINGLETHREADED not set or enabled, force patching "
"OpenGL to single "
"threaded to avoid crash !!!\n");
return "1";
}
}
char* ret = _mk3hook_ogl_fix_real_getenv(name);
if (!strcmp(name, "__GL_SINGLETHREADED")) {
if (ret == NULL || strcmp(name, "1") != 0) {
printf("!!! mk3hook: __GL_SINGLETHREADED not set or enabled, force patching OpenGL to single "
"threaded to avoid crash !!!\n");
return "1";
}
}
return ret;
return ret;
}
+77 -48
View File
@@ -14,13 +14,17 @@
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT "patch.sound.debug_output"
#define MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -62,8 +66,10 @@ static const struct util_options_def mk3hook_options_def[] = {
},
{
.name = MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS,
.description = "Enable this option when running 1st or 2nd. This uses different file system redirects for the "
"game directory as well as enables a fix. Without this, the game throws errors about not finding files",
.description = "Enable this option when running 1st or 2nd. This uses "
"different file system redirects for the "
"game directory as well as enables a fix. Without this, "
"the game throws errors about not finding files",
.param = 'x',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
@@ -111,22 +117,26 @@ static const struct util_options_def mk3hook_options_def[] = {
.default_value.b = false,
},
{
.name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -147,8 +157,9 @@ static const struct util_options_def mk3hook_options_def[] = {
},
{
.name = MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT,
.description = "Enable debug output for the fmod library. This requires you to use the fmodexL.so instead of "
"the standard fmodex.so",
.description = "Enable debug output for the fmod library. This "
"requires you to use the fmodexL.so instead of "
"the standard fmodex.so",
.param = 'r',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
@@ -185,46 +196,64 @@ static const struct util_options_defs mk3hook_options_defs = {
.ndefs = lengthof(mk3hook_options_def)
};
bool mk3hook_options_init(int argc, char** argv, struct mk3hook_options* options)
bool mk3hook_options_init(
int argc, char **argv, struct mk3hook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&mk3hook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&mk3hook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_GAME_SETTINGS);
options->game.sync_offset = util_options_get_int(options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_OFFSET);
options->game.sync_multiplier = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_MULTIPLIER);
options->game.music_vol = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_MUSIC_VOL);
options->game.sfx_vol = util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_SFX_VOL);
options->game.fs_1st_2nd = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sound.debug_output = util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_GAME_SETTINGS);
options->game.sync_offset =
util_options_get_int(options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_OFFSET);
options->game.sync_multiplier = util_options_get_double(
options_opt, MK3HOOK_OPTIONS_STR_GAME_SYNC_MULTIPLIER);
options->game.music_vol =
util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_MUSIC_VOL);
options->game.sfx_vol =
util_options_get_double(options_opt, MK3HOOK_OPTIONS_STR_GAME_SFX_VOL);
options->game.fs_1st_2nd =
util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_GAME_1ST_2ND_FS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sound.debug_output = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_SOUND_DEBUG_OUTPUT);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, MK3HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+41 -40
View File
@@ -7,54 +7,55 @@
#include "util/log.h"
struct mk3hook_options {
struct game {
const char* settings;
int32_t sync_offset;
double sync_multiplier;
double music_vol;
double sfx_vol;
bool fs_1st_2nd;
} game;
struct game {
const char *settings;
int32_t sync_offset;
double sync_multiplier;
double music_vol;
double sfx_vol;
bool fs_1st_2nd;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
bool debug_output;
} sound;
struct sound {
const char *device;
bool debug_output;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool mk3hook_options_init(int argc, char** argv, struct mk3hook_options* options);
bool mk3hook_options_init(
int argc, char **argv, struct mk3hook_options *options);
#endif
+162 -147
View File
@@ -15,8 +15,8 @@
#include "hook/patch/hook-mon.h"
#include "hook/patch/main-loop.h"
#include "hook/patch/microdog34.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -37,234 +37,249 @@ extern const uint8_t _binary_nxhook_hdd_raw_end[];
extern const uint8_t _binary_nxhook_dog_key_start[];
extern const uint8_t _binary_nxhook_dog_key_end[];
static void nxhook_bootstrapping(int argc, char** argv, struct nxhook_options* options, char** game_data_path)
static void nxhook_bootstrapping(
int argc,
char **argv,
struct nxhook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
if (!nxhook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void nxhook_patch_fs_init(struct nxhook_options *options)
{
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
}
static void nxhook_fs_redir_settings(struct nxhook_options *options)
{
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
hook_core_piu_log_init(argc, argv);
char *abs_path = util_fs_get_abs_path(options->game.settings);
if (!nxhook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void nxhook_patch_fs_init(struct nxhook_options* options)
static void nxhook_fs_redir_script(
struct nxhook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
char *path_tmp;
patch_redir_init();
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
static void nxhook_fs_redir_settings(struct nxhook_options* options)
static void nxhook_fs_redir_fonts(
struct nxhook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
char *path_tmp;
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
path_tmp = util_str_merge(game_data_path, "/MICROGBE.TTF");
cnh_redir_add("MICROGBE.TTF", path_tmp);
free(path_tmp);
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void nxhook_fs_redir_script(struct nxhook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
static void nxhook_fs_redir_fonts(struct nxhook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
path_tmp = util_str_merge(game_data_path, "/MICROGBE.TTF");
cnh_redir_add("MICROGBE.TTF", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/NXTW.TTF");
cnh_redir_add("NXTW.TTF", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/NXTW.TTF");
cnh_redir_add("NXTW.TTF", path_tmp);
free(path_tmp);
}
static void nxhook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
}
static void nxhook_fs_redirs_init(struct nxhook_options* options, const char* game_data_path)
static void nxhook_fs_redirs_init(
struct nxhook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nxhook_fs_redir_settings(options);
nxhook_fs_redir_script(options, game_data_path);
nxhook_fs_redir_fonts(options, game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nxhook_fs_redir_settings(options);
nxhook_fs_redir_script(options, game_data_path);
nxhook_fs_redir_fonts(options, game_data_path);
nxhook_fs_redir_usb();
nxhook_fs_redir_usb();
}
static void nxhook_patch_gfx_init(struct nxhook_options* options)
static void nxhook_patch_gfx_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void nxhook_patch_game_init(struct nxhook_options* options)
static void nxhook_patch_game_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.force_unlock) {
hook_nx_unlock_init();
}
if (options->game.force_unlock) {
hook_nx_unlock_init();
}
}
static void nxhook_patch_main_loop_init(struct nxhook_options* options)
static void nxhook_patch_main_loop_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
true, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void nxhook_patch_sound_init(struct nxhook_options* options)
static void nxhook_patch_sound_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_sound_init(options->patch.sound.device);
}
static void nxhook_patch_sigsegv_init(struct nxhook_options* options)
static void nxhook_patch_sigsegv_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void nxhook_patch_dongle_init()
{
patch_microdog34_init((const uint8_t*) _binary_nxhook_dog_key_start,
((uintptr_t) &_binary_nxhook_dog_key_end - (uintptr_t) &_binary_nxhook_dog_key_start));
patch_microdog34_init(
(const uint8_t *) _binary_nxhook_dog_key_start,
((uintptr_t) &_binary_nxhook_dog_key_end -
(uintptr_t) &_binary_nxhook_dog_key_start));
}
static void nxhook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_nxhook_hdd_raw_start,
((uintptr_t) &_binary_nxhook_hdd_raw_end - (uintptr_t) &_binary_nxhook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_nxhook_hdd_raw_start,
((uintptr_t) &_binary_nxhook_hdd_raw_end -
(uintptr_t) &_binary_nxhook_hdd_raw_start));
}
static void nxhook_patch_piuio_init(struct nxhook_options* options)
static void nxhook_patch_piuio_init(struct nxhook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
void nxhook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nxhook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nxhook_trap_before_main(int argc, char** argv)
void nxhook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct nxhook_options options;
char *game_data_path;
struct nxhook_options options;
nxhook_bootstrapping(argc, argv, &options, &game_data_path);
nxhook_patch_fs_init(&options);
nxhook_fs_redirs_init(&options, game_data_path);
nxhook_patch_gfx_init(&options);
nxhook_patch_game_init(&options);
nxhook_patch_main_loop_init(&options);
nxhook_patch_sound_init(&options);
nxhook_patch_sigsegv_init(&options);
nxhook_patch_dongle_init();
nxhook_patch_hdd_check_init();
nxhook_patch_piuio_init(&options);
nxhook_bootstrapping(argc, argv, &options, &game_data_path);
nxhook_patch_fs_init(&options);
nxhook_fs_redirs_init(&options, game_data_path);
nxhook_patch_gfx_init(&options);
nxhook_patch_game_init(&options);
nxhook_patch_main_loop_init(&options);
nxhook_patch_sound_init(&options);
nxhook_patch_sigsegv_init(&options);
nxhook_patch_dongle_init();
nxhook_patch_hdd_check_init();
nxhook_patch_piuio_init(&options);
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void nxhook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(nxhook_constructor);
+59 -39
View File
@@ -10,19 +10,24 @@
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
static const struct util_options_def nxhook_options_def[] = {
{
.name = NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK,
.description = "Force unlock the game. Modifies the current and any new PIUNX.INI settings file permanently",
.description = "Force unlock the game. Modifies the current and any "
"new PIUNX.INI settings file permanently",
.param = 'z',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
@@ -78,21 +83,24 @@ static const struct util_options_def nxhook_options_def[] = {
},
{
.name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -143,41 +151,53 @@ static const struct util_options_defs nxhook_options_defs = {
.ndefs = lengthof(nxhook_options_def)
};
bool nxhook_options_init(int argc, char** argv, struct nxhook_options* options)
bool nxhook_options_init(int argc, char **argv, struct nxhook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&nxhook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&nxhook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.force_unlock = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK);
options->game.settings = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.force_unlock =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_GAME_FORCE_UNLOCK);
options->game.settings =
util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb =
util_options_get_bool(options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, NXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.piuio.api_lib =
util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, NXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, NXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file =
util_options_get_str(options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, NXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+35 -35
View File
@@ -7,49 +7,49 @@
#include "util/log.h"
struct nxhook_options {
struct game {
bool force_unlock;
const char* settings;
} game;
struct game {
bool force_unlock;
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool nxhook_options_init(int argc, char** argv, struct nxhook_options* options);
bool nxhook_options_init(int argc, char **argv, struct nxhook_options *options);
#endif
+49 -48
View File
@@ -10,72 +10,73 @@
#include "util/log.h"
#include "util/str.h"
static FILE* _hook_nx_unlock_settings_file = NULL;
static FILE *_hook_nx_unlock_settings_file = NULL;
static enum cnh_result _hook_nx_unlock_filehook(struct cnh_filehook_irp *irp);
void hook_nx_unlock_init(void)
{
cnh_filehook_push_handler(_hook_nx_unlock_filehook);
cnh_filehook_push_handler(_hook_nx_unlock_filehook);
log_info("Initialized");
log_info("Initialized");
}
static enum cnh_result _hook_nx_unlock_filehook(struct cnh_filehook_irp *irp)
{
enum cnh_result result;
enum cnh_result result;
assert(irp);
assert(irp);
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN && irp->file != _hook_nx_unlock_settings_file) {
return cnh_filehook_invoke_next(irp);
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN &&
irp->file != _hook_nx_unlock_settings_file) {
return cnh_filehook_invoke_next(irp);
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN: {
/* Let it open the real file */
result = cnh_filehook_invoke_next(irp);
if (util_str_ends_with(irp->open_filename, ASSET_NX_SETTINGS_FILE_NAME)) {
if (result == CNH_RESULT_SUCCESS) {
log_debug("Intercepting settings file open");
_hook_nx_unlock_settings_file = irp->file;
}
}
break;
}
switch (irp->op) {
case CNH_FILEHOOK_IRP_OP_OPEN:
{
/* Let it open the real file */
result = cnh_filehook_invoke_next(irp);
case CNH_FILEHOOK_IRP_OP_READ: {
/* Let it read the real file */
result = cnh_filehook_invoke_next(irp);
if (util_str_ends_with(irp->open_filename, ASSET_NX_SETTINGS_FILE_NAME)) {
if (result == CNH_RESULT_SUCCESS) {
log_debug("Intercepting settings file open");
_hook_nx_unlock_settings_file = irp->file;
}
}
if (result == CNH_RESULT_SUCCESS) {
struct asset_nx_settings *settings =
(struct asset_nx_settings *) irp->read.bytes;
break;
}
asset_nx_settings_unlock_all(settings);
case CNH_FILEHOOK_IRP_OP_READ:
{
/* Let it read the real file */
result = cnh_filehook_invoke_next(irp);
log_debug(
"Applied unlock patch to loaded settings (buffer size %d)",
irp->read.pos);
}
if (result == CNH_RESULT_SUCCESS) {
struct asset_nx_settings* settings = (struct asset_nx_settings*) irp->read.bytes;
asset_nx_settings_unlock_all(settings);
log_debug("Applied unlock patch to loaded settings (buffer size %d)", irp->read.pos);
}
break;
}
case CNH_FILEHOOK_IRP_OP_CLOSE:
{
_hook_nx_unlock_settings_file = NULL;
result = cnh_filehook_invoke_next(irp);
break;
}
default:
result = cnh_filehook_invoke_next(irp);
break;
break;
}
return result;
case CNH_FILEHOOK_IRP_OP_CLOSE: {
_hook_nx_unlock_settings_file = NULL;
result = cnh_filehook_invoke_next(irp);
break;
}
default:
result = cnh_filehook_invoke_next(irp);
break;
}
return result;
}
+2 -1
View File
@@ -1,5 +1,6 @@
/**
* Patch module to force unlock all songs/features of the game without modifying the configuration stored on disk.
* Patch module to force unlock all songs/features of the game without modifying
* the configuration stored on disk.
*/
#ifndef HOOK_NX_UNLOCK_H
#define HOOK_NX_UNLOCK_H
+196 -179
View File
@@ -14,8 +14,8 @@
#include "hook/patch/microdog40.h"
#include "hook/patch/mounts.h"
#include "hook/patch/net-profile.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -39,280 +39,297 @@ extern const uint8_t _binary_nx2hook_hdd_raw_end[];
extern const uint8_t _binary_nx2hook_dog_key_start[];
extern const uint8_t _binary_nx2hook_dog_key_end[];
static void nx2hook_bootstrapping(int argc, char** argv, struct nx2hook_options* options, char** game_data_path)
static void nx2hook_bootstrapping(
int argc,
char **argv,
struct nx2hook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
if (!nx2hook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void nx2hook_patch_fs_init(struct nx2hook_options *options)
{
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
}
static void nx2hook_fs_redir_settings(struct nx2hook_options *options)
{
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
hook_core_piu_log_init(argc, argv);
char *abs_path = util_fs_get_abs_path(options->game.settings);
if (!nx2hook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void nx2hook_patch_fs_init(struct nx2hook_options* options)
static void nx2hook_fs_redir_script(
struct nx2hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
char *path_tmp;
patch_redir_init();
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
static void nx2hook_fs_redir_settings(struct nx2hook_options* options)
static void nx2hook_fs_redir_fonts(
struct nx2hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
char *path_tmp;
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
/* Fonts, game expects lower case files */
path_tmp = util_str_merge(game_data_path, "/nx.ttf");
cnh_redir_add("nx.ttf", path_tmp);
free(path_tmp);
char* abs_path = util_fs_get_abs_path(options->game.settings);
path_tmp = util_str_merge(game_data_path, "/nxcn.ttf");
cnh_redir_add("nxcn.ttf", path_tmp);
free(path_tmp);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
path_tmp = util_str_merge(game_data_path, "/nxpt.ttf");
cnh_redir_add("nxpt.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxtw.ttf");
cnh_redir_add("nxtw.ttf", path_tmp);
free(path_tmp);
}
static void nx2hook_fs_redir_script(struct nx2hook_options* options, const char* game_data_path)
static void nx2hook_fs_redir_mission(
struct nx2hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
char *path_tmp;
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
static void nx2hook_fs_redir_fonts(struct nx2hook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
/* Fonts, game expects lower case files */
path_tmp = util_str_merge(game_data_path, "/nx.ttf");
cnh_redir_add("nx.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxcn.ttf");
cnh_redir_add("nxcn.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxpt.ttf");
cnh_redir_add("nxpt.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxtw.ttf");
cnh_redir_add("nxtw.ttf", path_tmp);
free(path_tmp);
}
static void nx2hook_fs_redir_mission(struct nx2hook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
/* mission.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/mission.txt");
cnh_redir_add("/mission.txt", path_tmp);
free(path_tmp);
/* mission.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/mission.txt");
cnh_redir_add("/mission.txt", path_tmp);
free(path_tmp);
}
static void nx2hook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void nx2hook_fs_redirs_init(struct nx2hook_options* options, const char* game_data_path)
static void nx2hook_fs_redirs_init(
struct nx2hook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nx2hook_fs_redir_settings(options);
nx2hook_fs_redir_script(options, game_data_path);
nx2hook_fs_redir_fonts(options, game_data_path);
nx2hook_fs_redir_mission(options, game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nx2hook_fs_redir_settings(options);
nx2hook_fs_redir_script(options, game_data_path);
nx2hook_fs_redir_fonts(options, game_data_path);
nx2hook_fs_redir_mission(options, game_data_path);
nx2hook_fs_redir_usb();
nx2hook_fs_redir_usb();
}
static void nx2hook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_unlock_init();
patch_usb_mnt_init();
patch_usb_unlock_init();
}
static void nx2hook_patch_gfx_init(struct nx2hook_options* options)
static void nx2hook_patch_gfx_init(struct nx2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void nx2hook_patch_main_loop_init(struct nx2hook_options* options)
static void nx2hook_patch_main_loop_init(struct nx2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void nx2hook_patch_sound_init(struct nx2hook_options* options)
static void nx2hook_patch_sound_init(struct nx2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_sound_init(options->patch.sound.device);
}
static void nx2hook_patch_sigsegv_init(struct nx2hook_options* options)
static void nx2hook_patch_sigsegv_init(struct nx2hook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void nx2hook_patch_dongle_init()
{
patch_microdog40_init((const uint8_t*) _binary_nx2hook_dog_key_start,
((uintptr_t) &_binary_nx2hook_dog_key_end - (uintptr_t) &_binary_nx2hook_dog_key_start));
patch_microdog40_init(
(const uint8_t *) _binary_nx2hook_dog_key_start,
((uintptr_t) &_binary_nx2hook_dog_key_end -
(uintptr_t) &_binary_nx2hook_dog_key_start));
}
static void nx2hook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_nx2hook_hdd_raw_start,
((uintptr_t) &_binary_nx2hook_hdd_raw_end - (uintptr_t) &_binary_nx2hook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_nx2hook_hdd_raw_start,
((uintptr_t) &_binary_nx2hook_hdd_raw_end -
(uintptr_t) &_binary_nx2hook_hdd_raw_start));
}
static void nx2hook_patch_piuio_init(struct nx2hook_options* options)
static void nx2hook_patch_piuio_init(struct nx2hook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
static void nx2hook_patch_profile()
{
nx2hook_profile_gen_init();
nx2hook_profile_gen_init();
}
static void nx2hook_patch_pumpnet(struct nx2hook_options* options)
static void nx2hook_patch_pumpnet(struct nx2hook_options *options)
{
if (options->patch.net.server && options->patch.net.machine_id != 0) {
patch_net_profile_init(
ASSET_GAME_VERSION_NX2,
options->patch.net.server,
options->patch.net.machine_id,
options->patch.net.cert_dir_path,
options->patch.net.verbose_log_output);
}
if (options->patch.net.server && options->patch.net.machine_id != 0) {
patch_net_profile_init(
ASSET_GAME_VERSION_NX2,
options->patch.net.server,
options->patch.net.machine_id,
options->patch.net.cert_dir_path,
options->patch.net.verbose_log_output);
}
}
void nx2hook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nx2hook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nx2hook_trap_before_main(int argc, char** argv)
void nx2hook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct nx2hook_options options;
char *game_data_path;
struct nx2hook_options options;
nx2hook_bootstrapping(argc, argv, &options, &game_data_path);
nx2hook_patch_fs_init(&options);
nx2hook_fs_redirs_init(&options, game_data_path);
nx2hook_patch_fs_mounting_init();
nx2hook_patch_gfx_init(&options);
nx2hook_patch_main_loop_init(&options);
nx2hook_patch_sound_init(&options);
nx2hook_patch_sigsegv_init(&options);
nx2hook_patch_dongle_init();
nx2hook_patch_hdd_check_init();
nx2hook_patch_piuio_init(&options);
// Init order of pumpnet and auto profile generating important: pumpnet hook, if active, needs to be applied before
// the auto gen profile hook. Otherwise, the game detects that no profile is available and auto generates one even
// it should take the pumpnet route to grab a profile from a remote server
nx2hook_patch_pumpnet(&options);
nx2hook_patch_profile();
nx2hook_bootstrapping(argc, argv, &options, &game_data_path);
nx2hook_patch_fs_init(&options);
nx2hook_fs_redirs_init(&options, game_data_path);
nx2hook_patch_fs_mounting_init();
nx2hook_patch_gfx_init(&options);
nx2hook_patch_main_loop_init(&options);
nx2hook_patch_sound_init(&options);
nx2hook_patch_sigsegv_init(&options);
nx2hook_patch_dongle_init();
nx2hook_patch_hdd_check_init();
nx2hook_patch_piuio_init(&options);
// Init order of pumpnet and auto profile generating important: pumpnet hook,
// if active, needs to be applied before the auto gen profile hook. Otherwise,
// the game detects that no profile is available and auto generates one even
// it should take the pumpnet route to grab a profile from a remote server
nx2hook_patch_pumpnet(&options);
nx2hook_patch_profile();
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void nx2hook_trap_after_main(void)
{
patch_net_profile_shutdown();
patch_piuio_shutdown();
patch_net_profile_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(nx2hook_constructor);
+82 -53
View File
@@ -9,16 +9,23 @@
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT "patch.net_profile.verbose_log_output"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH "patch.net_profile.cert_dir_path"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
"patch.net_profile.machine_id"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT \
"patch.net_profile.verbose_log_output"
#define NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH \
"patch.net_profile.cert_dir_path"
#define NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define NX2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define NX2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define NX2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -73,22 +80,26 @@ const struct util_options_def nx2hook_options_def[] = {
.default_value.b = false,
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -102,21 +113,25 @@ const struct util_options_def nx2hook_options_def[] = {
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT,
.description = "Enable verbose log output for pumpnet related things, e.g. logging network traffic",
.description = "Enable verbose log output for pumpnet related things, "
"e.g. logging network traffic",
.param = 'v',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH,
.description = "Path to a folder containing the client key, certificate and CA bundle to enable https communication",
.description =
"Path to a folder containing the client key, certificate and CA "
"bundle to enable https communication",
.param = 'c',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -167,49 +182,63 @@ const struct util_options_defs nx2hook_options_defs = {
.ndefs = lengthof(nx2hook_options_def)
};
bool nx2hook_options_init(int argc, char** argv, struct nx2hook_options* options)
bool nx2hook_options_init(
int argc, char **argv, struct nx2hook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&nx2hook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&nx2hook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoull(
util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.net.verbose_log_output =
util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT);
options->patch.net.cert_dir_path =
util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH);
options->patch.piuio.api_lib = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoull(
util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.net.verbose_log_output = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_VERBOSE_LOG_OUTPUT);
options->patch.net.cert_dir_path = util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_CERT_DIR_PATH);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, NX2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, NX2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+41 -40
View File
@@ -7,55 +7,56 @@
#include "util/log.h"
struct nx2hook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
uint64_t machine_id;
bool verbose_log_output;
const char* cert_dir_path;
} net;
struct net {
const char *server;
uint64_t machine_id;
bool verbose_log_output;
const char *cert_dir_path;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool nx2hook_options_init(int argc, char** argv, struct nx2hook_options* options);
bool nx2hook_options_init(
int argc, char **argv, struct nx2hook_options *options);
#endif
+52 -46
View File
@@ -12,59 +12,65 @@
static bool nx2hook_profile_gen_is_creating_file;
// Do not use util_fs_path_exists here as this fopens and causes an endless recursion
static bool nx2hook_profile_gen_check_if_exists(const char* path)
// Do not use util_fs_path_exists here as this fopens and causes an endless
// recursion
static bool nx2hook_profile_gen_check_if_exists(const char *path)
{
return access(path, F_OK) != -1;
return access(path, F_OK) != -1;
}
static enum cnh_result nx2hook_profile_gen_filehook(struct cnh_filehook_irp *irp)
static enum cnh_result
nx2hook_profile_gen_filehook(struct cnh_filehook_irp *irp)
{
// nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls when creating the save/rank files
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN || nx2hook_profile_gen_is_creating_file) {
return cnh_filehook_invoke_next(irp);
}
if (util_str_ends_with(irp->open_filename, "nx2save.bin") &&
!nx2hook_profile_gen_check_if_exists(irp->open_filename)) {
nx2hook_profile_gen_is_creating_file = true;
struct asset_nx2_usb_save* save = asset_nx2_usb_save_new();
asset_nx2_usb_save_finalize(save);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nx2_usb_save_save_to_file(irp->open_filename, save, true)) {
log_error("Saving generated nx2save.bin file to %s failed", irp->open_filename);
}
free(save);
nx2hook_profile_gen_is_creating_file = false;
}
if (util_str_ends_with(irp->open_filename, "nx2rank.bin") &&
!nx2hook_profile_gen_check_if_exists(irp->open_filename)) {
nx2hook_profile_gen_is_creating_file = true;
struct asset_nx2_usb_rank* rank = asset_nx2_usb_rank_new();
asset_nx2_usb_rank_finalize(rank);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nx2_usb_rank_save_to_file(irp->open_filename, rank, true)) {
log_error("Saving generated nx2rank.bin file to %s failed", irp->open_filename);
}
free(rank);
nx2hook_profile_gen_is_creating_file = false;
}
// nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls
// when creating the save/rank files
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN ||
nx2hook_profile_gen_is_creating_file) {
return cnh_filehook_invoke_next(irp);
}
if (util_str_ends_with(irp->open_filename, "nx2save.bin") &&
!nx2hook_profile_gen_check_if_exists(irp->open_filename)) {
nx2hook_profile_gen_is_creating_file = true;
struct asset_nx2_usb_save *save = asset_nx2_usb_save_new();
asset_nx2_usb_save_finalize(save);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nx2_usb_save_save_to_file(irp->open_filename, save, true)) {
log_error(
"Saving generated nx2save.bin file to %s failed", irp->open_filename);
}
free(save);
nx2hook_profile_gen_is_creating_file = false;
}
if (util_str_ends_with(irp->open_filename, "nx2rank.bin") &&
!nx2hook_profile_gen_check_if_exists(irp->open_filename)) {
nx2hook_profile_gen_is_creating_file = true;
struct asset_nx2_usb_rank *rank = asset_nx2_usb_rank_new();
asset_nx2_usb_rank_finalize(rank);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nx2_usb_rank_save_to_file(irp->open_filename, rank, true)) {
log_error(
"Saving generated nx2rank.bin file to %s failed", irp->open_filename);
}
free(rank);
nx2hook_profile_gen_is_creating_file = false;
}
return cnh_filehook_invoke_next(irp);
}
void nx2hook_profile_gen_init(void)
{
cnh_filehook_push_handler(nx2hook_profile_gen_filehook);
cnh_filehook_push_handler(nx2hook_profile_gen_filehook);
}
+185 -169
View File
@@ -16,8 +16,8 @@
#include "hook/patch/main-loop.h"
#include "hook/patch/microdog40.h"
#include "hook/patch/mounts.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
@@ -41,268 +41,284 @@ extern const uint8_t _binary_nxahook_hdd_raw_end[];
extern const uint8_t _binary_nxahook_dog_key_start[];
extern const uint8_t _binary_nxahook_dog_key_end[];
static void nxahook_bootstrapping(int argc, char** argv, struct nxahook_options* options, char** game_data_path)
static void nxahook_bootstrapping(
int argc,
char **argv,
struct nxahook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
if (!nxahook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void nxahook_patch_fs_init(struct nxahook_options *options)
{
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
}
static void nxahook_fs_redir_settings(struct nxahook_options *options)
{
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
hook_core_piu_log_init(argc, argv);
char *abs_path = util_fs_get_abs_path(options->game.settings);
if (!nxahook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
log_info("Initializing, piu game data path: %s", *game_data_path);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void nxahook_patch_fs_init(struct nxahook_options* options)
static void nxahook_fs_redir_script(
struct nxahook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
char *path_tmp;
patch_redir_init();
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
static void nxahook_fs_redir_settings(struct nxahook_options* options)
static void nxahook_fs_redir_fonts(
struct nxahook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(options);
log_assert(game_data_path);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
char *path_tmp;
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
/* Fonts, game expects lower case files */
path_tmp = util_str_merge(game_data_path, "/nx.ttf");
cnh_redir_add("nx.ttf", path_tmp);
free(path_tmp);
char* abs_path = util_fs_get_abs_path(options->game.settings);
path_tmp = util_str_merge(game_data_path, "/nxcn.ttf");
cnh_redir_add("nxcn.ttf", path_tmp);
free(path_tmp);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
path_tmp = util_str_merge(game_data_path, "/nxpt.ttf");
cnh_redir_add("nxpt.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxtw.ttf");
cnh_redir_add("nxtw.ttf", path_tmp);
free(path_tmp);
}
static void nxahook_fs_redir_script(struct nxahook_options* options, const char* game_data_path)
static void nxahook_fs_redir_mission(
struct nxahook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
char *path_tmp;
path_tmp = util_str_merge(game_data_path, "/SCRIPT");
cnh_redir_add("/SCRIPT", path_tmp);
free(path_tmp);
}
/* mission.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/mission.txt");
cnh_redir_add("/mission.txt", path_tmp);
free(path_tmp);
static void nxahook_fs_redir_fonts(struct nxahook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
/* Fonts, game expects lower case files */
path_tmp = util_str_merge(game_data_path, "/nx.ttf");
cnh_redir_add("nx.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxcn.ttf");
cnh_redir_add("nxcn.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxpt.ttf");
cnh_redir_add("nxpt.ttf", path_tmp);
free(path_tmp);
path_tmp = util_str_merge(game_data_path, "/nxtw.ttf");
cnh_redir_add("nxtw.ttf", path_tmp);
free(path_tmp);
}
static void nxahook_fs_redir_mission(struct nxahook_options* options, const char* game_data_path)
{
log_assert(options);
log_assert(game_data_path);
char* path_tmp;
/* mission.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/mission.txt");
cnh_redir_add("/mission.txt", path_tmp);
free(path_tmp);
/* ufo.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/ufo.txt");
cnh_redir_add("/ufo.txt", path_tmp);
free(path_tmp);
/* ufo.txt, game expects lower case file */
path_tmp = util_str_merge(game_data_path, "/ufo.txt");
cnh_redir_add("/ufo.txt", path_tmp);
free(path_tmp);
}
static void nxahook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void nxahook_fs_redirs_init(struct nxahook_options* options, const char* game_data_path)
static void nxahook_fs_redirs_init(
struct nxahook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nxahook_fs_redir_settings(options);
nxahook_fs_redir_script(options, game_data_path);
nxahook_fs_redir_fonts(options, game_data_path);
nxahook_fs_redir_mission(options, game_data_path);
/* Expecting all assets in the piu game (asset) folder. redirects for files
that are not in there by default for reasons */
nxahook_fs_redir_settings(options);
nxahook_fs_redir_script(options, game_data_path);
nxahook_fs_redir_fonts(options, game_data_path);
nxahook_fs_redir_mission(options, game_data_path);
nxahook_fs_redir_usb();
nxahook_fs_redir_usb();
}
static void nxahook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_unlock_init();
patch_usb_mnt_init();
patch_usb_unlock_init();
}
static void nxahook_patch_gfx_init(struct nxahook_options* options)
static void nxahook_patch_gfx_init(struct nxahook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void nxahook_patch_main_loop_init(struct nxahook_options* options)
static void nxahook_patch_main_loop_init(struct nxahook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
}
static void nxahook_patch_sound_init(struct nxahook_options* options)
static void nxahook_patch_sound_init(struct nxahook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_sound_init(options->patch.sound.device);
}
static void nxahook_patch_sigsegv_init(struct nxahook_options* options)
static void nxahook_patch_sigsegv_init(struct nxahook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void nxahook_patch_dongle_init()
{
patch_microdog40_init((const uint8_t*) _binary_nxahook_dog_key_start,
((uintptr_t) &_binary_nxahook_dog_key_end - (uintptr_t) &_binary_nxahook_dog_key_start));
patch_microdog40_init(
(const uint8_t *) _binary_nxahook_dog_key_start,
((uintptr_t) &_binary_nxahook_dog_key_end -
(uintptr_t) &_binary_nxahook_dog_key_start));
}
static void nxahook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_nxahook_hdd_raw_start,
((uintptr_t) &_binary_nxahook_hdd_raw_end - (uintptr_t) &_binary_nxahook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_nxahook_hdd_raw_start,
((uintptr_t) &_binary_nxahook_hdd_raw_end -
(uintptr_t) &_binary_nxahook_hdd_raw_start));
}
static void nxahook_patch_piuio_init(struct nxahook_options* options)
static void nxahook_patch_piuio_init(struct nxahook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
static void nxahook_patch_profile()
{
nxahook_profile_gen_init();
nxahook_profile_gen_init();
}
void nxahook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nxahook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void nxahook_trap_before_main(int argc, char** argv)
void nxahook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct nxahook_options options;
char *game_data_path;
struct nxahook_options options;
nxahook_bootstrapping(argc, argv, &options, &game_data_path);
nxahook_patch_fs_init(&options);
nxahook_fs_redirs_init(&options, game_data_path);
nxahook_patch_fs_mounting_init();
nxahook_patch_gfx_init(&options);
nxahook_patch_main_loop_init(&options);
nxahook_patch_sound_init(&options);
nxahook_patch_sigsegv_init(&options);
nxahook_patch_dongle_init();
nxahook_patch_hdd_check_init();
nxahook_patch_piuio_init(&options);
nxahook_patch_profile();
nxahook_bootstrapping(argc, argv, &options, &game_data_path);
nxahook_patch_fs_init(&options);
nxahook_fs_redirs_init(&options, game_data_path);
nxahook_patch_fs_mounting_init();
nxahook_patch_gfx_init(&options);
nxahook_patch_main_loop_init(&options);
nxahook_patch_sound_init(&options);
nxahook_patch_sigsegv_init(&options);
nxahook_patch_dongle_init();
nxahook_patch_hdd_check_init();
nxahook_patch_piuio_init(&options);
nxahook_patch_profile();
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void nxahook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(nxahook_constructor);
+69 -45
View File
@@ -9,14 +9,19 @@
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
#define NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
#define NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
"patch.net_profile.machine_id"
#define NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -71,22 +76,26 @@ const struct util_options_def nxahook_options_def[] = {
.default_value.b = false,
},
{
.name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
.name =
NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (F2) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -100,7 +109,8 @@ const struct util_options_def nxahook_options_def[] = {
},
{
.name = NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -151,45 +161,59 @@ const struct util_options_defs nxahook_options_defs = {
.ndefs = lengthof(nxahook_options_def)
};
bool nxahook_options_init(int argc, char** argv, struct nxahook_options* options)
bool nxahook_options_init(
int argc, char **argv, struct nxahook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&nxahook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&nxahook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
options->patch.net.machine_id = strtoul(
util_options_get_str(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
NULL,
16);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, NXAHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, NXAHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+39 -38
View File
@@ -7,53 +7,54 @@
#include "util/log.h"
struct nxahook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
uint32_t machine_id;
} net;
struct net {
const char *server;
uint32_t machine_id;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool nxahook_options_init(int argc, char** argv, struct nxahook_options* options);
bool nxahook_options_init(
int argc, char **argv, struct nxahook_options *options);
#endif
+90 -84
View File
@@ -12,97 +12,103 @@
static bool nxahook_profile_gen_is_creating_file;
// Do not use util_fs_path_exists here as this fopens and causes an endless recursion
static bool nxahook_profile_gen_check_if_exists(const char* path)
// Do not use util_fs_path_exists here as this fopens and causes an endless
// recursion
static bool nxahook_profile_gen_check_if_exists(const char *path)
{
return access(path, F_OK) != -1;
return access(path, F_OK) != -1;
}
static enum cnh_result nxahook_profile_gen_filehook(struct cnh_filehook_irp *irp)
static enum cnh_result
nxahook_profile_gen_filehook(struct cnh_filehook_irp *irp)
{
// nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls when creating the save/rank files
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN || nxahook_profile_gen_is_creating_file) {
return cnh_filehook_invoke_next(irp);
}
if (util_str_ends_with(irp->open_filename, "nxasave.bin") &&
!nxahook_profile_gen_check_if_exists(irp->open_filename)) {
char* path_only;
char* path_nx2;
struct asset_nxa_usb_save* save;
nxahook_profile_gen_is_creating_file = true;
/* Check if a nx2save.bin exists and skip generating a new nxasave
file because the game migrates everything from the nx2 file */
path_only = util_fs_get_path_to_file(irp->open_filename);
path_nx2 = util_str_merge(path_only, "/nx2save.bin");
free(path_only);
if (util_fs_path_exists(path_nx2)) {
free(path_nx2);
log_info("nx2save.bin exists, don't create new nxasave.bin");
nxahook_profile_gen_is_creating_file = false;
return cnh_filehook_invoke_next(irp);
}
free(path_nx2);
save = asset_nxa_usb_save_new();
asset_nxa_usb_save_finalize(save);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nxa_usb_save_save_to_file(irp->open_filename, save, true)) {
log_error("Saving generated nxasave.bin file to %s failed", irp->open_filename);
}
free(save);
nxahook_profile_gen_is_creating_file = false;
}
if (util_str_ends_with(irp->open_filename, "nxarank.bin") &&
!nxahook_profile_gen_check_if_exists(irp->open_filename)) {
char* path_only;
char* path_nx2;
struct asset_nxa_usb_rank* rank;
nxahook_profile_gen_is_creating_file = true;
/* Check if a nx2rank.bin exists and skip generating a new nxarank
file because the game migrates everything from the nx2 file */
path_only = util_fs_get_path_to_file(irp->open_filename);
path_nx2 = util_str_merge(path_only, "/nx2rank.bin");
free(path_only);
if (util_fs_path_exists(path_nx2)) {
free(path_nx2);
log_info("nx2rank.bin exists, don't create new nxarank.bin");
nxahook_profile_gen_is_creating_file = false;
return cnh_filehook_invoke_next(irp);
}
free(path_nx2);
rank = asset_nxa_usb_rank_new();
asset_nxa_usb_rank_finalize(rank);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nxa_usb_rank_save_to_file(irp->open_filename, rank, true)) {
log_error("Saving generated nxarank.bin file to %s failed", irp->open_filename);
}
free(rank);
nxahook_profile_gen_is_creating_file = false;
}
// nx2hook_profile_gen_is_creating_file: Avoid recursion of any file calls
// when creating the save/rank files
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN ||
nxahook_profile_gen_is_creating_file) {
return cnh_filehook_invoke_next(irp);
}
if (util_str_ends_with(irp->open_filename, "nxasave.bin") &&
!nxahook_profile_gen_check_if_exists(irp->open_filename)) {
char *path_only;
char *path_nx2;
struct asset_nxa_usb_save *save;
nxahook_profile_gen_is_creating_file = true;
/* Check if a nx2save.bin exists and skip generating a new nxasave
file because the game migrates everything from the nx2 file */
path_only = util_fs_get_path_to_file(irp->open_filename);
path_nx2 = util_str_merge(path_only, "/nx2save.bin");
free(path_only);
if (util_fs_path_exists(path_nx2)) {
free(path_nx2);
log_info("nx2save.bin exists, don't create new nxasave.bin");
nxahook_profile_gen_is_creating_file = false;
return cnh_filehook_invoke_next(irp);
}
free(path_nx2);
save = asset_nxa_usb_save_new();
asset_nxa_usb_save_finalize(save);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nxa_usb_save_save_to_file(irp->open_filename, save, true)) {
log_error(
"Saving generated nxasave.bin file to %s failed", irp->open_filename);
}
free(save);
nxahook_profile_gen_is_creating_file = false;
}
if (util_str_ends_with(irp->open_filename, "nxarank.bin") &&
!nxahook_profile_gen_check_if_exists(irp->open_filename)) {
char *path_only;
char *path_nx2;
struct asset_nxa_usb_rank *rank;
nxahook_profile_gen_is_creating_file = true;
/* Check if a nx2rank.bin exists and skip generating a new nxarank
file because the game migrates everything from the nx2 file */
path_only = util_fs_get_path_to_file(irp->open_filename);
path_nx2 = util_str_merge(path_only, "/nx2rank.bin");
free(path_only);
if (util_fs_path_exists(path_nx2)) {
free(path_nx2);
log_info("nx2rank.bin exists, don't create new nxarank.bin");
nxahook_profile_gen_is_creating_file = false;
return cnh_filehook_invoke_next(irp);
}
free(path_nx2);
rank = asset_nxa_usb_rank_new();
asset_nxa_usb_rank_finalize(rank);
log_info("No %s file found, generate new", irp->open_filename);
if (!asset_nxa_usb_rank_save_to_file(irp->open_filename, rank, true)) {
log_error(
"Saving generated nxarank.bin file to %s failed", irp->open_filename);
}
free(rank);
nxahook_profile_gen_is_creating_file = false;
}
return cnh_filehook_invoke_next(irp);
}
void nxahook_profile_gen_init(void)
{
cnh_filehook_push_handler(nxahook_profile_gen_filehook);
cnh_filehook_push_handler(nxahook_profile_gen_filehook);
}
+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
+153 -139
View File
@@ -20,10 +20,10 @@
#include "hook/patch/main-loop.h"
#include "hook/patch/mounts.h"
#include "hook/patch/network.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/redir.h"
#include "hook/patch/piuio.h"
#include "hook/patch/ram-wipe.h"
#include "hook/patch/redir.h"
#include "hook/patch/sigsegv.h"
#include "hook/patch/sound.h"
#include "hook/patch/usb-emu.h"
@@ -45,248 +45,262 @@ extern const uint8_t _binary_prihook_hdd_raw_end[];
extern const uint8_t _binary_prihook_hasp_key_start[];
extern const uint8_t _binary_prihook_hasp_key_end[];
static void prihook_bootstrapping(int argc, char** argv, struct prihook_options* options, char** game_data_path)
static void prihook_bootstrapping(
int argc,
char **argv,
struct prihook_options *options,
char **game_data_path)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(game_data_path);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!prihook_options_init(argc, argv, options)) {
exit(0);
}
if (!prihook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
*game_data_path =
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_fix_locale();
hook_core_piu_utils_fix_locale();
log_info("Initializing, piu game data path: %s", *game_data_path);
log_info("Initializing, piu game data path: %s", *game_data_path);
}
static void prihook_patch_fs_init(struct prihook_options* options)
static void prihook_patch_fs_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void prihook_fs_redir_settings(struct prihook_options* options)
static void prihook_fs_redir_settings(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char *abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/SETTINGS", abs_path);
free(abs_path);
} else {
log_warn("No settings path specified");
}
}
static void prihook_fs_redir_usb()
{
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
/* Needed on newer kernels */
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
patch_usbfs_init();
}
static void prihook_fs_redirs_init(struct prihook_options* options, const char* game_data_path)
static void prihook_fs_redirs_init(
struct prihook_options *options, const char *game_data_path)
{
log_assert(options);
log_assert(game_data_path);
log_assert(options);
log_assert(game_data_path);
prihook_fs_redir_settings(options);
prihook_fs_redir_settings(options);
prihook_fs_redir_usb();
prihook_fs_redir_usb();
}
static void prihook_patch_fs_mounting_init()
{
patch_mounts_init();
patch_mounts_init();
patch_usb_mnt_init();
patch_usb_mnt_init();
}
static void prihook_patch_gfx_init(struct prihook_options* options)
static void prihook_patch_gfx_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
patch_gfx_init();
patch_gfx_init();
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
if (options->patch.gfx.windowed) {
patch_gfx_force_window_mode();
}
}
static void prihook_patch_main_loop_init(struct prihook_options* options)
static void prihook_patch_main_loop_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
patch_main_loop_init(
false, options->patch.main_loop.disable_built_in_inputs, false);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
if (options->patch.main_loop.x11_input_handler_api_lib) {
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
options->patch.main_loop.x11_input_handler_api_lib);
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
free(abs_path_x11_input_hook_lib);
}
patch_block_keyboard_grab_init();
patch_block_keyboard_grab_init();
}
static void prihook_patch_sound_init(struct prihook_options* options)
static void prihook_patch_sound_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
patch_sound_init(options->patch.sound.device);
patch_axmier_block_init();
}
static void prihook_patch_sigsegv_init(struct prihook_options* options)
static void prihook_patch_sigsegv_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
}
static void prihook_patch_dongle_init()
{
patch_hasp_init((const uint8_t*) _binary_prihook_hasp_key_start,
((uintptr_t) &_binary_prihook_hasp_key_end - (uintptr_t) &_binary_prihook_hasp_key_start));
patch_hasp_init(
(const uint8_t *) _binary_prihook_hasp_key_start,
((uintptr_t) &_binary_prihook_hasp_key_end -
(uintptr_t) &_binary_prihook_hasp_key_start));
}
static void prihook_patch_hdd_check_init()
{
patch_hdd_check_init((const uint8_t*) _binary_prihook_hdd_raw_start,
((uintptr_t) &_binary_prihook_hdd_raw_end - (uintptr_t) &_binary_prihook_hdd_raw_start));
patch_hdd_check_init(
(const uint8_t *) _binary_prihook_hdd_raw_start,
((uintptr_t) &_binary_prihook_hdd_raw_end -
(uintptr_t) &_binary_prihook_hdd_raw_start));
}
static void prihook_patch_ram_wipe_init()
{
patch_ram_wipe_init();
patch_ram_wipe_init();
}
static void prihook_patch_piuio_init(struct prihook_options* options)
static void prihook_patch_piuio_init(struct prihook_options *options)
{
log_assert(options);
log_assert(options);
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
/* Hook before IO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
patch_usb_init_fix_init();
patch_usb_emu_init();
patch_usb_init_fix_init();
patch_usb_emu_init();
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
static void prihook_patch_net_init(struct prihook_options* options)
static void prihook_patch_net_init(struct prihook_options *options)
{
patch_blacklist_url_init();
/* update server */
patch_blacklist_url_add("http://update_kr");
/* game server */
patch_blacklist_url_add("http://www2.piugame.com");
patch_blacklist_url_init();
/* update server */
patch_blacklist_url_add("http://update_kr");
/* game server */
patch_blacklist_url_add("http://www2.piugame.com");
patch_network_init();
patch_network_init();
if (options->patch.net.server) {
char* address;
uint16_t port;
if (options->patch.net.server) {
char *address;
uint16_t port;
if (!util_net_split_ipv4_str(options->patch.net.server, &address, &port)) {
log_warn("Invalid format for option network address specified, ignored");
} else {
patch_network_redirect_server_address("115.68.108.183", address, (uint16_t) port);
free(address);
}
if (!util_net_split_ipv4_str(options->patch.net.server, &address, &port)) {
log_warn("Invalid format for option network address specified, ignored");
} else {
// Redirect to avoid phoning home if no server address is set
patch_network_redirect_server_address("115.68.108.183", "127.0.0.1", 12345);
patch_network_redirect_server_address(
"115.68.108.183", address, (uint16_t) port);
free(address);
}
} else {
// Redirect to avoid phoning home if no server address is set
patch_network_redirect_server_address("115.68.108.183", "127.0.0.1", 12345);
}
// Idk what this address is...redirect to something save for now
patch_network_redirect_server_address("45.76.222.114", "127.0.0.1", 12345);
// Idk what this address is...redirect to something save for now
patch_network_redirect_server_address("45.76.222.114", "127.0.0.1", 12345);
}
static void prihook_patch_usb_init()
{
prihook_usb_updates_init();
prihook_usb_updates_init();
}
void prihook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void prihook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void prihook_trap_before_main(int argc, char** argv)
void prihook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
char* game_data_path;
struct prihook_options options;
char *game_data_path;
struct prihook_options options;
prihook_bootstrapping(argc, argv, &options, &game_data_path);
prihook_patch_fs_init(&options);
prihook_fs_redirs_init(&options, game_data_path);
prihook_patch_fs_mounting_init();
prihook_patch_gfx_init(&options);
prihook_patch_main_loop_init(&options);
prihook_patch_sound_init(&options);
prihook_patch_sigsegv_init(&options);
prihook_patch_dongle_init();
prihook_patch_hdd_check_init();
prihook_patch_ram_wipe_init();
prihook_patch_piuio_init(&options);
prihook_patch_net_init(&options);
prihook_patch_usb_init();
prihook_bootstrapping(argc, argv, &options, &game_data_path);
prihook_patch_fs_init(&options);
prihook_fs_redirs_init(&options, game_data_path);
prihook_patch_fs_mounting_init();
prihook_patch_gfx_init(&options);
prihook_patch_main_loop_init(&options);
prihook_patch_sound_init(&options);
prihook_patch_sigsegv_init(&options);
prihook_patch_dongle_init();
prihook_patch_hdd_check_init();
prihook_patch_ram_wipe_init();
prihook_patch_piuio_init(&options);
prihook_patch_net_init(&options);
prihook_patch_usb_init();
free(game_data_path);
free(game_data_path);
log_info("Hooking finished");
log_info("Hooking finished");
}
void prihook_trap_after_main(void)
{
patch_piuio_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(prihook_constructor);
+62 -40
View File
@@ -9,13 +9,17 @@
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
"patch.hook_main_loop.disable_built_in_inputs"
#define PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
"patch_hook_main_loop.x11_input_handler"
#define PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER "patch.net.server"
#define PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
#define PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
#define PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
"patch.sigsegv.halt_on_segv"
#define PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -70,29 +74,34 @@ const struct util_options_def prihook_options_def[] = {
.default_value.b = false,
},
{
.name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), service (PRI) and clear (F3)",
.name =
PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
.description = "Disable the built in keyboard inputs for test (F1), "
"service (PRI) and clear (F3)",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_BOOL,
.default_value.b = false,
},
{
.name = PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER,
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.description =
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
.param = 'n',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -143,41 +152,54 @@ const struct util_options_defs prihook_options_defs = {
.ndefs = lengthof(prihook_options_def)
};
bool prihook_options_init(int argc, char** argv, struct prihook_options* options)
bool prihook_options_init(
int argc, char **argv, struct prihook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&prihook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&prihook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.settings = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib =
util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER);
options->patch.piuio.api_lib = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv =
util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.settings =
util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.gfx.windowed = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
options_opt,
PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
options->patch.net.server =
util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_NET_SERVER);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.sound.device =
util_options_get_str(options_opt, PRIHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
options->log.file = util_options_get_str(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, PRIHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}
+38 -37
View File
@@ -7,52 +7,53 @@
#include "util/log.h"
struct prihook_options {
struct game {
const char* settings;
} game;
struct game {
const char *settings;
} game;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct patch {
struct gfx {
bool windowed;
} gfx;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct hook_mon {
bool file;
bool fs;
bool io;
bool open;
bool usb;
} hook_mon;
struct main_loop {
bool disable_built_in_inputs;
const char* x11_input_handler_api_lib;
} main_loop;
struct main_loop {
bool disable_built_in_inputs;
const char *x11_input_handler_api_lib;
} main_loop;
struct net {
const char* server;
} net;
struct net {
const char *server;
} net;
struct piuio {
const char* api_lib;
bool exit_test_serv;
} piuio;
struct piuio {
const char *api_lib;
bool exit_test_serv;
} piuio;
struct sound {
const char* device;
} sound;
struct sound {
const char *device;
} sound;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct sigsegv {
bool halt_on_segv;
} sigsegv;
} patch;
struct log {
const char* file;
enum util_log_level level;
} log;
struct log {
const char *file;
enum util_log_level level;
} log;
};
bool prihook_options_init(int argc, char** argv, struct prihook_options* options);
bool prihook_options_init(
int argc, char **argv, struct prihook_options *options);
#endif
+14 -12
View File
@@ -6,22 +6,24 @@
#include "util/log.h"
static enum cnh_result prihook_usb_updates_filehook(struct cnh_filehook_irp *irp)
static enum cnh_result
prihook_usb_updates_filehook(struct cnh_filehook_irp *irp)
{
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN) {
return cnh_filehook_invoke_next(irp);
}
if (!strcmp(irp->open_filename, "/mnt/0/prime_") || !strcmp(irp->open_filename, "/mnt/1/prime_")) {
log_info("Blocking usb update %s", irp->open_filename);
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
}
if (irp->op != CNH_FILEHOOK_IRP_OP_OPEN) {
return cnh_filehook_invoke_next(irp);
}
if (!strcmp(irp->open_filename, "/mnt/0/prime_") ||
!strcmp(irp->open_filename, "/mnt/1/prime_")) {
log_info("Blocking usb update %s", irp->open_filename);
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
}
return cnh_filehook_invoke_next(irp);
}
void prihook_usb_updates_init(void)
{
cnh_filehook_push_handler(prihook_usb_updates_filehook);
cnh_filehook_push_handler(prihook_usb_updates_filehook);
}
+154 -148
View File
@@ -11,9 +11,9 @@
#include "hook/core/piu-utils.h"
#include "hook/patch/hook-mon.h"
#include "hook/patch/piuio.h"
#include "hook/patch/piuio-exit.h"
#include "hook/patch/piuio-khack.h"
#include "hook/patch/piuio.h"
#include "hook/patch/redir.h"
#include "hook/patch/usb-emu.h"
#include "hook/patch/usb-init-fix.h"
@@ -31,201 +31,207 @@
#include "options.h"
static void prohook_bootstrapping(int argc, char** argv, struct prohook_options* options)
static void
prohook_bootstrapping(int argc, char **argv, struct prohook_options *options)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
log_assert(argc >= 0);
log_assert(argv);
log_assert(options);
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
return;
}
hook_core_piu_log_init(argc, argv);
hook_core_piu_log_init(argc, argv);
if (!prohook_options_init(argc, argv, options)) {
exit(0);
}
if (!prohook_options_init(argc, argv, options)) {
exit(0);
}
hook_core_piu_log_info(argc, argv);
hook_core_piu_log_info(argc, argv);
hook_core_piu_utils_verify_root_user();
hook_core_piu_utils_verify_root_user();
log_info("Initializing");
log_info("Initializing");
}
static void prohook_patch_fs_init(struct prohook_options* options)
static void prohook_patch_fs_init(struct prohook_options *options)
{
log_assert(options);
log_assert(options);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_hook_mon_init(
options->patch.hook_mon.io,
options->patch.hook_mon.file,
options->patch.hook_mon.fs,
options->patch.hook_mon.usb,
options->patch.hook_mon.open);
patch_redir_init();
patch_redir_init();
}
static void prohook_fs_redir_settings(struct prohook_options* options)
static void prohook_fs_redir_settings(struct prohook_options *options)
{
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info("Settings path %s does not exist, creating", options->game.settings);
if (options->game.settings) {
if (!util_fs_path_exists(options->game.settings)) {
log_info(
"Settings path %s does not exist, creating", options->game.settings);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
char* abs_path = util_fs_get_abs_path(options->game.settings);
cnh_redir_add("/data", abs_path);
free(abs_path);
} else {
log_warn("No settings (data) path specified");
}
}
static void prohook_fs_redir_data(struct prohook_options* options)
{
if (options->game.data) {
char* abs_path = util_fs_get_abs_path(options->game.data);
cnh_redir_add("/game", abs_path);
free(abs_path);
} else {
log_warn("No data (game) path specified");
}
}
static void prohook_fs_redirs_init(struct prohook_options* options)
{
log_assert(options);
prohook_fs_redir_settings(options);
prohook_fs_redir_data(options);
}
static void prohook_patch_sigsegv_init(struct prohook_options* options)
{
log_assert(options);
/* seems like pump pro doesn't like it when injecting our own signal
handler. game crashes instantly when adding it. */
/*
patch_sigsegv_init();
*/
}
static void prohook_patch_x11_event_loop_init(struct prohook_options* options)
{
patch_x11_event_loop_init();
// Register up to two X11 input handlers for piuio and piubtn
if (options->patch.x11_event_loop.api_lib) {
char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib);
patch_x11_event_loop_add_input_handler(abs_path_lib);
free(abs_path_lib);
if (!util_fs_mkdir(options->game.settings)) {
log_error("Creating directory %s failed", options->game.settings);
}
}
if (options->patch.x11_event_loop.api_lib2) {
char* abs_path_lib = util_fs_get_abs_path(options->patch.x11_event_loop.api_lib2);
char *abs_path = util_fs_get_abs_path(options->game.settings);
patch_x11_event_loop_add_input_handler(abs_path_lib);
free(abs_path_lib);
}
cnh_redir_add("/data", abs_path);
free(abs_path);
} else {
log_warn("No settings (data) path specified");
}
}
static void prohook_patch_usbprofiles(struct prohook_options* options)
static void prohook_fs_redir_data(struct prohook_options *options)
{
propatch_usb_fix_init(
options->patch.usb_profile.device_nodes,
options->patch.usb_profile.p1_bus_port,
options->patch.usb_profile.p2_bus_port);
if (options->game.data) {
char *abs_path = util_fs_get_abs_path(options->game.data);
cnh_redir_add("/game", abs_path);
free(abs_path);
} else {
log_warn("No data (game) path specified");
}
}
static void prohook_patch_piuio_init(struct prohook_options* options)
static void prohook_fs_redirs_init(struct prohook_options *options)
{
log_assert(options);
log_assert(options);
// The order of layering the hooks is important here because of deps
// 1. Fix low level libusb thing with init
// 2. Turn the ITG 2 piuio kernel hack calls into normal piuio ctrl transfer calls
// 3. Introduce an abstraction layer to allow, to abstract libusb0.1 and allow adding fakedevs
// required for further software emulation
// 4. Exit module to allow exiting the game with test + service
// 5. Software emulation layer for piuio
//
// For example, the kernel hack layer takes care of removing that, so software
// emulation code doesn't have to bother with that edge case. Furthermore, it allows you
// to use the game with real hardware without any additional software emulation layers
// that have to detour to real hardware again
patch_usb_init_fix_init();
patch_piuio_khack_init();
patch_usb_emu_init();
/* Hook before PIUIO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
if (options->patch.piuio.api_lib) {
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
prohook_fs_redir_settings(options);
prohook_fs_redir_data(options);
}
static void prohook_patch_piubtn_init(struct prohook_options* options)
static void prohook_patch_sigsegv_init(struct prohook_options *options)
{
if (options->patch.piubtn.api_lib) {
char* abs_path_btnlib = util_fs_get_abs_path(options->patch.piubtn.api_lib);
log_assert(options);
patch_piubtn_init(abs_path_btnlib);
free(abs_path_btnlib);
}
/* seems like pump pro doesn't like it when injecting our own signal
handler. game crashes instantly when adding it. */
/*
patch_sigsegv_init();
*/
}
static void prohook_patch_x11_event_loop_init(struct prohook_options *options)
{
patch_x11_event_loop_init();
// Register up to two X11 input handlers for piuio and piubtn
if (options->patch.x11_event_loop.api_lib) {
char *abs_path_lib =
util_fs_get_abs_path(options->patch.x11_event_loop.api_lib);
patch_x11_event_loop_add_input_handler(abs_path_lib);
free(abs_path_lib);
}
if (options->patch.x11_event_loop.api_lib2) {
char *abs_path_lib =
util_fs_get_abs_path(options->patch.x11_event_loop.api_lib2);
patch_x11_event_loop_add_input_handler(abs_path_lib);
free(abs_path_lib);
}
}
static void prohook_patch_usbprofiles(struct prohook_options *options)
{
propatch_usb_fix_init(
options->patch.usb_profile.device_nodes,
options->patch.usb_profile.p1_bus_port,
options->patch.usb_profile.p2_bus_port);
}
static void prohook_patch_piuio_init(struct prohook_options *options)
{
log_assert(options);
// The order of layering the hooks is important here because of deps
// 1. Fix low level libusb thing with init
// 2. Turn the ITG 2 piuio kernel hack calls into normal piuio ctrl transfer
// calls
// 3. Introduce an abstraction layer to allow, to abstract libusb0.1 and allow
// adding fakedevs
// required for further software emulation
// 4. Exit module to allow exiting the game with test + service
// 5. Software emulation layer for piuio
//
// For example, the kernel hack layer takes care of removing that, so software
// emulation code doesn't have to bother with that edge case. Furthermore, it
// allows you to use the game with real hardware without any additional
// software emulation layers that have to detour to real hardware again
patch_usb_init_fix_init();
patch_piuio_khack_init();
patch_usb_emu_init();
/* Hook before PIUIO emulation */
if (options->patch.piuio.exit_test_serv) {
patch_piuio_exit_init();
}
if (options->patch.piuio.api_lib) {
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
patch_piuio_init(abs_path_iolib);
free(abs_path_iolib);
}
}
static void prohook_patch_piubtn_init(struct prohook_options *options)
{
if (options->patch.piubtn.api_lib) {
char *abs_path_btnlib = util_fs_get_abs_path(options->patch.piubtn.api_lib);
patch_piubtn_init(abs_path_btnlib);
free(abs_path_btnlib);
}
}
void prohook_constructor(void)
{
/* Nothing here */
/* Nothing here */
}
void prohook_destructor(void)
{
/* Nothing here */
/* Nothing here */
}
void prohook_trap_before_main(int argc, char** argv)
void prohook_trap_before_main(int argc, char **argv)
{
log_assert(argc >= 0);
log_assert(argv);
log_assert(argc >= 0);
log_assert(argv);
struct prohook_options options;
struct prohook_options options;
prohook_bootstrapping(argc, argv, &options);
prohook_patch_fs_init(&options);
prohook_fs_redirs_init(&options);
prohook_patch_sigsegv_init(&options);
prohook_patch_x11_event_loop_init(&options);
prohook_patch_usbprofiles(&options);
prohook_patch_piuio_init(&options);
prohook_patch_piubtn_init(&options);
prohook_bootstrapping(argc, argv, &options);
prohook_patch_fs_init(&options);
prohook_fs_redirs_init(&options);
prohook_patch_sigsegv_init(&options);
prohook_patch_x11_event_loop_init(&options);
prohook_patch_usbprofiles(&options);
prohook_patch_piuio_init(&options);
prohook_patch_piubtn_init(&options);
log_info("Hooking finished");
log_info("Hooking finished");
}
void prohook_trap_after_main(void)
{
propatch_usb_fix_shutdown();
patch_piubtn_shutdown();
patch_piuio_shutdown();
propatch_usb_fix_shutdown();
patch_piubtn_shutdown();
patch_piuio_shutdown();
}
LIB_MAIN_CONSTRUCTOR(prohook_constructor);
+72 -48
View File
@@ -11,12 +11,18 @@
#define PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
#define PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB "patch.piubtn.emu_lib"
#define PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
#define PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT "patch.usb_profile.p1.bus_port"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT "patch.usb_profile.p2.bus_port"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES "patch.usb_profile.dev_nodes"
#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER "patch_x11_event_loop.input_handler_lib"
#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2 "patch_x11_event_loop.input_handler_lib2"
#define PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
"patch.piuio_exit.test_serv"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT \
"patch.usb_profile.p1.bus_port"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT \
"patch.usb_profile.p2.bus_port"
#define PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES \
"patch.usb_profile.dev_nodes"
#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER \
"patch_x11_event_loop.input_handler_lib"
#define PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2 \
"patch_x11_event_loop.input_handler_lib2"
#define PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
#define PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
@@ -72,14 +78,16 @@ static const struct util_options_def prohook_options_def[] = {
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB,
.description = "Path to library implementing the piubtn api for piubtn emulation",
.description =
"Path to library implementing the piubtn api for piubtn emulation",
.param = 'b',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
.description = "Path to library implementing the piuio api for piuio emulation",
.description =
"Path to library implementing the piuio api for piuio emulation",
.param = 'p',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -93,7 +101,8 @@ static const struct util_options_def prohook_options_def[] = {
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT,
.description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 1 when a USB thumb "
.description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot "
"to assign to Player 1 when a USB thumb "
"drive is plugged in",
.param = 'a',
.type = UTIL_OPTIONS_TYPE_STR,
@@ -101,7 +110,8 @@ static const struct util_options_def prohook_options_def[] = {
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT,
.description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot to assign to Player 2 when a USB thumb "
.description = "Bus and port (format: X-X, e.g. 1-2) of the USB slot "
"to assign to Player 2 when a USB thumb "
"drive is plugged in",
.param = 'k',
.type = UTIL_OPTIONS_TYPE_STR,
@@ -109,7 +119,8 @@ static const struct util_options_def prohook_options_def[] = {
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES,
.description = "Device nodes of plugged in USB thumb drives to consider for mounting for usb profiles, format: "
.description = "Device nodes of plugged in USB thumb drives to "
"consider for mounting for usb profiles, format: "
"sdX,sdY e.g. sde,sdf",
.param = 't',
.type = UTIL_OPTIONS_TYPE_STR,
@@ -117,14 +128,16 @@ static const struct util_options_def prohook_options_def[] = {
},
{
.name = PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER,
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a library implementing the x11-input-handler "
"api to capture X11 keyboard inputs",
.param = 'q',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
},
{
{
.name = PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2,
.description = "Path to a second library implementing the x11-input-handler api to capture X11 keyboard inputs",
.description = "Path to a second library implementing the "
"x11-input-handler api to capture X11 keyboard inputs",
.param = 'r',
.type = UTIL_OPTIONS_TYPE_STR,
.default_value.str = NULL,
@@ -154,44 +167,55 @@ static const struct util_options_defs prohook_options_defs = {
.ndefs = lengthof(prohook_options_def)
};
bool prohook_options_init(int argc, char** argv, struct prohook_options* options)
bool prohook_options_init(
int argc, char **argv, struct prohook_options *options)
{
log_assert(argv);
log_assert(options);
log_assert(argv);
log_assert(options);
struct util_options_opts* options_opt;
struct util_options_opts *options_opt;
util_options_init(argc, argv);
options_opt = util_options_get(&prohook_options_defs);
util_options_init(argc, argv);
options_opt = util_options_get(&prohook_options_defs);
if (!options_opt) {
return false;
}
if (!options_opt) {
return false;
}
options->game.data = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_DATA);
options->game.settings = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.hook_mon.file = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.piubtn.api_lib = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB);
options->patch.piuio.api_lib = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv =
util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.usb_profile.device_nodes =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES);
options->patch.usb_profile.p1_bus_port =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT);
options->patch.usb_profile.p2_bus_port =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT);
options->patch.x11_event_loop.api_lib =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER);
options->patch.x11_event_loop.api_lib2 =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2);
options->log.file = util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level =
(enum util_log_level) util_options_get_int(options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
options->game.data =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_DATA);
options->game.settings =
util_options_get_str(options_opt, PROHOOK_OPTIONS_STR_GAME_SETTINGS);
options->patch.hook_mon.file = util_options_get_bool(
options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
options->patch.hook_mon.fs =
util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
options->patch.hook_mon.io =
util_options_get_bool(options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
options->patch.hook_mon.open = util_options_get_bool(
options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
options->patch.hook_mon.usb = util_options_get_bool(
options_opt, PROHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
options->patch.piubtn.api_lib = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUBTN_EMU_LIB);
options->patch.piuio.api_lib = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
options->patch.piuio.exit_test_serv = util_options_get_bool(
options_opt, PROHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
options->patch.usb_profile.device_nodes = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_DEV_NODES);
options->patch.usb_profile.p1_bus_port = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P1_BUS_PORT);
options->patch.usb_profile.p2_bus_port = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_USB_PROFILE_P2_BUS_PORT);
options->patch.x11_event_loop.api_lib = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER);
options->patch.x11_event_loop.api_lib2 = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_X11_EVENT_LOOP_INPUT_HANDLER2);
options->log.file = util_options_get_str(
options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
options->log.level = (enum util_log_level) util_options_get_int(
options_opt, PROHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
return true;
return true;
}

Some files were not shown because too many files have changed in this diff Show More