mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2026-09-28 09:47:55 +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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user