PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
sio2man_hook.c
1#include <stdio.h>
2#include <string.h>
3#include <thsemap.h>
4
5#include "ioplib.h"
6#include "sio2man.h"
7#include "sio2man_hook.h"
8
9// #define DEBUG //comment out this line when not debugging
10#include "module_debug.h"
11
12#define PORT_NR 3
13
14static int lock_sema = -1;
15static int lock_sema2 = -1;
16static u16 hooked_version = 0;
17
18
19// sio2man function typedefs
20typedef void (*psio2_transfer_init)(void);
21typedef int (*psio2_transfer)(sio2_transfer_data_t *td);
22typedef void (*psio2_transfer_reset)(void);
23
24// Original sio2man function pointers
25psio2_transfer_init _23_psio2_pad_transfer_init;
26psio2_transfer_init _24_psio2_mc_transfer_init;
27psio2_transfer_init _46_psio2_pad_transfer_init;
28psio2_transfer_init _47_psio2_mc_transfer_init;
29psio2_transfer_init _48_psio2_mtap_transfer_init;
30psio2_transfer_init _49_psio2_rm_transfer_init;
31psio2_transfer_init _50_psio2_unk_transfer_init;
32psio2_transfer _25_psio2_transfer;
33psio2_transfer _51_psio2_transfer;
34psio2_transfer_reset _26_psio2_transfer_reset;
35psio2_transfer_reset _52_psio2_transfer_reset;
36
37// Generic sio2man init function
38static void _sio2_transfer_init(psio2_transfer_init init_func)
39{
40 //M_DEBUG("%s\n", __FUNCTION__);
41
42 WaitSema(lock_sema);
43 init_func();
44}
45
46// Generic sio2man transfer function
47static int _sio2_transfer(psio2_transfer transfer_func, sio2_transfer_data_t *td)
48{
49 int rv, i;
50
51 //M_DEBUG("%s\n", __FUNCTION__);
52
53 // Do not allow transfers to/from our used port
54 for (i = 0; i < 16; i++) {
55 // Last transfer, we're ok.
56 if (td->regdata[i] == 0)
57 break;
58
59 // Wrong port, abort.
60 if ((td->regdata[i] & 3) == PORT_NR)
61 return 1;
62 }
63
64 WaitSema(lock_sema2);
65 rv = transfer_func(td);
66 SignalSema(lock_sema2);
67
68 return rv;
69}
70
71// Generic sio2man transfer_reset function
72static void _sio2_transfer_reset(psio2_transfer_reset reset_func)
73{
74 //M_DEBUG("%s\n", __FUNCTION__);
75
76 reset_func();
77 SignalSema(lock_sema);
78}
79
80// Hooked sio2man functions
81static void _23_sio2_pad_transfer_init() { _sio2_transfer_init(_23_psio2_pad_transfer_init); }
82static void _24_sio2_mc_transfer_init() { _sio2_transfer_init(_24_psio2_mc_transfer_init); }
83static void _46_sio2_pad_transfer_init() { _sio2_transfer_init(_46_psio2_pad_transfer_init); }
84static void _47_sio2_mc_transfer_init() { _sio2_transfer_init(_47_psio2_mc_transfer_init); }
85static void _48_sio2_mtap_transfer_init() { _sio2_transfer_init(_48_psio2_mtap_transfer_init); }
86static void _49_sio2_rm_transfer_init() { _sio2_transfer_init(_49_psio2_rm_transfer_init); }
87static void _50_sio2_unk_transfer_init() { _sio2_transfer_init(_50_psio2_unk_transfer_init); }
88static void _26_sio2_transfer_reset() { _sio2_transfer_reset(_26_psio2_transfer_reset); }
89static void _52_sio2_transfer_reset() { _sio2_transfer_reset(_52_psio2_transfer_reset); }
90static int _25_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_25_psio2_transfer, td); }
91static int _51_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_51_psio2_transfer, td); }
92
93static void _sio2man_unhook(iop_library_t *lib)
94{
95 if (hooked_version == 0) {
96 M_DEBUG("Warning: trying to unhook sio2man while not hooked\n");
97 return;
98 }
99
100 ioplib_hookExportEntry(lib, 23, _23_psio2_pad_transfer_init);
101 ioplib_hookExportEntry(lib, 24, _24_psio2_mc_transfer_init);
102 ioplib_hookExportEntry(lib, 25, _25_psio2_transfer);
103 ioplib_hookExportEntry(lib, 26, _26_psio2_transfer_reset);
104 ioplib_hookExportEntry(lib, 46, _46_psio2_pad_transfer_init);
105 ioplib_hookExportEntry(lib, 47, _47_psio2_mc_transfer_init);
106 ioplib_hookExportEntry(lib, 48, _48_psio2_mtap_transfer_init);
107
108 if ((hooked_version >= IRX_VER(1, 2)) && (hooked_version < IRX_VER(2, 0))) {
109 // Only for the newer rom0:XSIO2MAN
110 // Assume all v1.x libraries to use this interface (reset at 50)
111 ioplib_hookExportEntry(lib, 49, _51_psio2_transfer);
112 ioplib_hookExportEntry(lib, 50, _52_psio2_transfer_reset);
113 } else /*if (hooked_version >= IRX_VER(2, 3))*/ {
114 // Only for the newer rom1:SIO2MAN
115 // Assume all v2.x libraries to use this interface (reset at 52)
116 ioplib_hookExportEntry(lib, 49, _49_psio2_rm_transfer_init);
117 ioplib_hookExportEntry(lib, 50, _50_psio2_unk_transfer_init);
118 ioplib_hookExportEntry(lib, 51, _51_psio2_transfer);
119 ioplib_hookExportEntry(lib, 52, _52_psio2_transfer_reset);
120 }
121
122 hooked_version = 0;
123}
124
125static void _sio2man_hook(iop_library_t *lib)
126{
127 if (hooked_version != 0) {
128 M_DEBUG("Warning: trying to hook sio2man version 0x%x\n", lib->version);
129 M_DEBUG(" while version 0x%x already hooked\n", hooked_version);
130 return;
131 }
132
133 // Only the newer sio2man libraries (with reset functions) are supported
134 if (lib->version > IRX_VER(1, 1)) {
135 M_DEBUG("Installing sio2man hooks for version 0x%x\n", lib->version);
136
137 _23_psio2_pad_transfer_init = ioplib_hookExportEntry(lib, 23, _23_sio2_pad_transfer_init);
138 // Lock sio2 to prevent race conditions with MC/PAD libraries
139 _23_psio2_pad_transfer_init();
140
141 _24_psio2_mc_transfer_init = ioplib_hookExportEntry(lib, 24, _24_sio2_mc_transfer_init);
142 _25_psio2_transfer = ioplib_hookExportEntry(lib, 25, _25_sio2_transfer);
143 _26_psio2_transfer_reset = ioplib_hookExportEntry(lib, 26, _26_sio2_transfer_reset);
144 _46_psio2_pad_transfer_init = ioplib_hookExportEntry(lib, 46, _46_sio2_pad_transfer_init);
145 _47_psio2_mc_transfer_init = ioplib_hookExportEntry(lib, 47, _47_sio2_mc_transfer_init);
146 _48_psio2_mtap_transfer_init = ioplib_hookExportEntry(lib, 48, _48_sio2_mtap_transfer_init);
147
148 if ((lib->version >= IRX_VER(1, 2)) && (lib->version < IRX_VER(2, 0))) {
149 // Only for the newer rom0:XSIO2MAN
150 // Assume all v1.x libraries to use this interface (reset at 50)
151 _51_psio2_transfer = ioplib_hookExportEntry(lib, 49, _51_sio2_transfer);
152 _52_psio2_transfer_reset = ioplib_hookExportEntry(lib, 50, _52_sio2_transfer_reset);
153 } else /*if (lib->version >= IRX_VER(2, 3))*/ {
154 // Only for the newer rom1:SIO2MAN
155 // Assume all v2.x libraries to use this interface (reset at 52)
156 _49_psio2_rm_transfer_init = ioplib_hookExportEntry(lib, 49, _49_sio2_rm_transfer_init);
157 _50_psio2_unk_transfer_init = ioplib_hookExportEntry(lib, 50, _50_sio2_unk_transfer_init);
158 _51_psio2_transfer = ioplib_hookExportEntry(lib, 51, _51_sio2_transfer);
159 _52_psio2_transfer_reset = ioplib_hookExportEntry(lib, 52, _52_sio2_transfer_reset);
160 }
161
162 // Unlock sio2
163 _26_psio2_transfer_reset();
164
165 hooked_version = lib->version;
166 } else {
167 M_DEBUG("ERROR: sio2man version 0x%x not supported\n", lib->version);
168 }
169}
170
171int (*pRegisterLibraryEntries)(iop_library_t *lib);
172static int hookRegisterLibraryEntries(iop_library_t *lib)
173{
174 M_DEBUG("RegisterLibraryEntries: %s 0x%x\n", lib->name, lib->version);
175
176 if (!strcmp(lib->name, "sio2man"))
177 _sio2man_hook(lib);
178
179 return pRegisterLibraryEntries(lib);
180}
181
182int sio2man_hook_init()
183{
184 iop_sema_t sema;
185 iop_library_t *lib;
186
187 M_DEBUG("%s\n", __FUNCTION__);
188
189 // Create semaphore for locking sio2man exclusively
190 sema.attr = 1;
191 sema.initial = 1;
192 sema.max = 1;
193 sema.option = 0;
194 lock_sema = CreateSema(&sema);
195 lock_sema2 = CreateSema(&sema);
196
197 // Hook into 'loadcore' so we know when sio2man is loaded in the future
198 lib = ioplib_getByName("loadcore");
199 if (lib == NULL) {
200 DeleteSema(lock_sema);
201 DeleteSema(lock_sema2);
202 return -1;
203 }
204 pRegisterLibraryEntries = ioplib_hookExportEntry(lib, 6, hookRegisterLibraryEntries);
205
206 // Hook into 'sio2man' now if it's already loaded
207 lib = ioplib_getByName("sio2man");
208 if (lib != NULL) {
209 _sio2man_hook(lib);
210 ioplib_relinkExports(lib);
211 }
212
213 return 0;
214}
215
216void sio2man_hook_deinit()
217{
218 iop_library_t *lib;
219
220 M_DEBUG("%s\n", __FUNCTION__);
221
222 // Unhook 'sio2man'
223 lib = ioplib_getByName("sio2man");
224 if (lib != NULL) {
225 _sio2man_unhook(lib);
226 ioplib_relinkExports(lib);
227 }
228
229 // Unhook 'loadcore'
230 ioplib_hookExportEntry(lib, 6, pRegisterLibraryEntries);
231
232 // Delete locking semaphore
233 DeleteSema(lock_sema);
234 DeleteSema(lock_sema2);
235}
236
237void sio2man_hook_sio2_lock()
238{
239 // Lock sio2man driver so we can use it exclusively
240 WaitSema(lock_sema);
241 WaitSema(lock_sema2);
242}
243
244void sio2man_hook_sio2_unlock()
245{
246 // Unlock sio2man driver
247 SignalSema(lock_sema2);
248 SignalSema(lock_sema);
249}