mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2026-09-28 17:58:01 +03:00
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:
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,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
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
+483
-431
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -9,4 +9,4 @@
|
||||
*/
|
||||
void patch_redir_init();
|
||||
|
||||
#endif //PATCH_REDIR_H
|
||||
#endif // PATCH_REDIR_H
|
||||
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user