sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
sio2man_hook.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9#
10# taken from MX4SIO driver for simplicity.
11# all credits go to maximus32
12*/
13
14#include <stdio.h>
15#include <string.h>
16#include <thsemap.h>
17#include <intrman.h>
18
19#include "ioplib.h"
20#include "sio2man.h"
21#include "sio2man_hook.h"
22
23// #define DEBUG //comment out this line when not debugging
24#include "module_debug.h"
25
26#define PORT_NR 3
27#ifndef M_DEBUG
28#define M_DEBUG DPRINTF
29#endif
30
31// sio2man function typedefs
32typedef void (*psio2_transfer_init)(void);
33typedef int (*psio2_transfer)(sio2_transfer_data_t *td);
34typedef void (*psio2_transfer_reset)(void);
35
37{
38 iop_library_t *m_lib;
39 // Original sio2man function pointers
40 psio2_transfer_init m_23_psio2_pad_transfer_init;
41#ifdef PORT_NR
42 psio2_transfer m_25_psio2_transfer;
43#endif
44 psio2_transfer_reset m_26_psio2_transfer_reset;
45};
46
47static struct sio2man_hook_data g_hook_data[2];
48static iop_library_t *g_loadcore_lib;
49#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
50static iop_library_t *g_intrman_lib;
51static int (*g_sio2man_intr_handler_ptr)(void *arg);
52static void *g_sio2man_intr_arg_ptr;
53#endif
54
55#ifdef PORT_NR
56static sio2_transfer_data_t g_null_td;
57// Generic sio2man transfer function
58static int _sio2_transfer(psio2_transfer transfer_func, sio2_transfer_data_t *td)
59{
60 unsigned int i;
61
62 //M_DEBUG("%s\n", __FUNCTION__);
63
64 // Do not allow transfers to/from our used port
65 for (i = 0; i < (sizeof(td->regdata)/sizeof(td->regdata[0])); i++) {
66 // Last transfer, we're ok.
67 if (td->regdata[i] == 0)
68 break;
69
70 // Wrong port; behave as a no-op.
71 // This will allow the transfer reset behavior for old library to work.
72 if ((td->regdata[i] & 3) == PORT_NR)
73 return transfer_func(&g_null_td);
74 }
75
76 return transfer_func(td);
77}
78
79// Hooked sio2man functions
80static int _1_25_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(g_hook_data[0].m_25_psio2_transfer, td); }
81static int _2_25_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(g_hook_data[1].m_25_psio2_transfer, td); }
82#endif
83
84static void unhook_loadcore(void);
85#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
86static void unhook_intrman(void);
87#endif
88
89static void _sio2man_hook(iop_library_t *lib)
90{
91 int state;
92
93 // Disable interrupts to prevent race conditions with MC/PAD libraries
94 CpuSuspendIntr(&state);
95 // Only the newest sio2man libraries (using one semaphore for locks for all devices) are supported
96 switch (lib->version)
97 {
98 case IRX_VER(1, 2):
99 case IRX_VER(2, 7):
100 {
101 int major_version;
102
103 M_DEBUG("Installing sio2man hooks for version 0x%x\n", lib->version);
104
105 major_version = ((lib->version >> 8) & 0xFF);
106 if (g_hook_data[major_version - 1].m_lib) {
107 M_DEBUG("Warning: trying to hook sio2man version 0x%x\n", lib->version);
108 M_DEBUG(" while version 0x%x already hooked\n", g_hook_data[major_version - 1].m_lib->version);
109 }
110 g_hook_data[major_version - 1].m_lib = lib;
111 g_hook_data[major_version - 1].m_23_psio2_pad_transfer_init = lib->exports[23];
112#ifdef PORT_NR
113 g_hook_data[major_version - 1].m_25_psio2_transfer = ioplib_hookSameExportEntries(lib, 25, (major_version == 1) ? &_1_25_sio2_transfer : &_2_25_sio2_transfer);
114#endif
115 g_hook_data[major_version - 1].m_26_psio2_transfer_reset = lib->exports[26];
116#ifdef PORT_NR
117 ioplib_relinkExports(lib);
118#endif
119 break;
120 }
121 default:
122 {
123 M_DEBUG("ERROR: sio2man version 0x%x not supported\n", lib->version);
124 break;
125 }
126 }
127 if (g_hook_data[0].m_lib && g_hook_data[1].m_lib)
128 unhook_loadcore();
129 CpuResumeIntr(state);
130}
131
132#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
133// intrman hook
134static int (*pRegisterIntrHandler)(int irq, int mode, int (*handler)(void *), void *arg);
135static int hookRegisterIntrHandler(int irq, int mode, int (*handler)(void *), void *arg)
136{
137 int ret;
138 M_DEBUG("RegisterIntrHandler irq: %i, handler @ 0x%p\n", irq, handler);
139
140 ret = pRegisterIntrHandler(irq, mode, handler, arg);
141 // If handler already exists or other error, then do not save handler
142 if (ret)
143 return ret;
144 // SIO2 interrupt
145 if (irq == IOP_IRQ_SIO2 && !g_sio2man_intr_handler_ptr) {
146 g_sio2man_intr_handler_ptr = handler;
147 g_sio2man_intr_arg_ptr = arg;
148 M_DEBUG("Got SIO2MAN intr handler @ 0x%p, arg @ 0x%p\n", handler, arg);
149 unhook_intrman();
150 }
151 return ret;
152}
153#endif
154
155// loadcore hook
156static int (*pRegisterLibraryEntries)(iop_library_t *lib);
157static int hookRegisterLibraryEntries(iop_library_t *lib)
158{
159 int ret;
160 M_DEBUG("RegisterLibraryEntries: %s 0x%x\n", lib->name, lib->version);
161
162 ret = pRegisterLibraryEntries(lib);
163 // If library already exists or other error, then do not hook
164 if (ret)
165 return ret;
166 if (!strcmp(lib->name, "sio2man"))
167 _sio2man_hook(lib);
168 return ret;
169}
170
171static void unhook_loadcore(void)
172{
173 int state;
174
175 CpuSuspendIntr(&state);
176 if (g_loadcore_lib) {
177 if (pRegisterLibraryEntries)
178 ioplib_hookSameExportEntries(g_loadcore_lib, 6, pRegisterLibraryEntries);
179 g_loadcore_lib = NULL;
180 }
181 CpuResumeIntr(state);
182}
183
184#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
185static void unhook_intrman(void)
186{
187 int state;
188
189 CpuSuspendIntr(&state);
190 if (g_intrman_lib) {
191 if (pRegisterIntrHandler)
192 ioplib_hookSameExportEntries(g_intrman_lib, 4, pRegisterIntrHandler);
193 g_intrman_lib = NULL;
194 }
195 CpuResumeIntr(state);
196}
197#endif
198
199static int generic_hook_iterate_cb(iop_library_t *lib, void *userdata)
200{
201 (void)userdata;
202 if (userdata && !*(iop_library_t **)userdata)
203 *(iop_library_t **)userdata = lib;
204 return 1;
205}
206
207static int sio2man_hook_iterate_cb(iop_library_t *lib, void *userdata)
208{
209 (void)userdata;
210 switch ((lib->version >> 8) & 0xFF)
211 {
212 case 1:
213 case 2:
214 {
215 _sio2man_hook(lib);
216 return (g_hook_data[0].m_lib && g_hook_data[1].m_lib) ? 1 : 0;
217 }
218 default:
219 return 1;
220 }
221}
222
223int sio2man_hook_init()
224{
225 M_DEBUG("%s\n", __FUNCTION__);
226
227#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
228 {
229 intrman_internals_t *intrman_internals;
230
231 intrman_internals = GetIntrmanInternalData();
232 // Get sio2man intr handler
233 g_sio2man_intr_handler_ptr = intrman_internals->interrupt_handler_table[IOP_IRQ_SIO2].handler;
234 g_sio2man_intr_arg_ptr = intrman_internals->interrupt_handler_table[IOP_IRQ_SIO2].userdata;
235 }
236#endif
237
238 // Hook into 'sio2man' now if it's already loaded
239 if (!ioplib_iterateByName("sio2man", &sio2man_hook_iterate_cb, NULL)) {
240 // Hook into 'loadcore' so we know when sio2man is loaded in the future
241 ioplib_iterateByName("loadcore", &generic_hook_iterate_cb, &g_loadcore_lib);
242#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
243 // Hook into 'intrman' so we can get its handlers when they are registered
244 ioplib_iterateByName("intrman", &generic_hook_iterate_cb, &g_intrman_lib);
245#endif
246 if (!g_loadcore_lib)
247 return -1;
248#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
249 if (!g_intrman_lib)
250 return -1;
251#endif
252 pRegisterLibraryEntries = ioplib_hookSameExportEntries(g_loadcore_lib, 6, hookRegisterLibraryEntries);
253 ioplib_relinkExports(g_loadcore_lib);
254#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
255 pRegisterIntrHandler = ioplib_hookSameExportEntries(g_intrman_lib, 4, hookRegisterIntrHandler);
256 ioplib_relinkExports(g_intrman_lib);
257#endif
258 }
259
260 return 0;
261}
262
263void sio2man_hook_deinit()
264{
265 unsigned int i;
266
267 M_DEBUG("%s\n", __FUNCTION__);
268
269 // Unhook 'sio2man'
270 for (i = 0; i < (sizeof(g_hook_data)/sizeof(g_hook_data[0])); i += 1) {
271 if (g_hook_data[i].m_lib) {
272#ifdef PORT_NR
273 if (g_hook_data[i].m_25_psio2_transfer) {
274 ioplib_hookSameExportEntries(g_hook_data[i].m_lib, 25, g_hook_data[i].m_25_psio2_transfer);
275 g_hook_data[i].m_25_psio2_transfer = NULL;
276 }
277 ioplib_relinkExports(g_hook_data[i].m_lib);
278#endif
279 g_hook_data[i].m_lib = NULL;
280 }
281 }
282
283 unhook_loadcore();
284#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
285 unhook_intrman();
286#endif
287}
288
289void sio2man_hook_sio2_lock()
290{
291 // Lock sio2man driver so we can use it exclusively
292 if (g_hook_data[1].m_23_psio2_pad_transfer_init)
293 g_hook_data[1].m_23_psio2_pad_transfer_init();
294}
295
296void sio2man_hook_sio2_unlock()
297{
298 // Unlock sio2man driver
299 if (g_hook_data[1].m_26_psio2_transfer_reset)
300 g_hook_data[1].m_26_psio2_transfer_reset();
301}
302
303#if SIO2MAN_HOOK_SUPPORT_SET_INTR_HANDLER
304void sio2man_hook_sio2_set_intr_handler(int (*handler)(void *userdata), void *userdata)
305{
306 intrman_internals_t *intrman_internals;
307 int state;
308
309 intrman_internals = GetIntrmanInternalData();
310 CpuSuspendIntr(&state);
311 intrman_internals->interrupt_handler_table[IOP_IRQ_SIO2].handler = handler ? handler : g_sio2man_intr_handler_ptr;
312 intrman_internals->interrupt_handler_table[IOP_IRQ_SIO2].userdata = handler ? userdata : g_sio2man_intr_arg_ptr;
313 CpuResumeIntr(state);
314}
315#endif
int CpuResumeIntr(int state)
Definition intrman.c:217
int CpuSuspendIntr(int *state)
Definition intrman.c:195
Definition main.c:40