PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
freemtap.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007 Lukasz Bruun <mail@lukasz.dk>
3 *
4 * See the file LICENSE included with this distribution for licensing terms.
5 */
6
12#include "types.h"
13#include "irx.h"
14#include "stdio.h"
15#include "loadcore.h"
16#include "thevent.h"
17#include "thbase.h"
18#include "xsio2man.h"
19#include "freemtap.h"
20
21extern struct irx_export_table _exp_mtapman;
22
23#define BANNER "FREEMTAP %s\n"
24#define VERSION "v1.0"
25
26#define EF_UPDATE_SLOTS 0x1
27#define EF_EXIT_THREAD 0x2
28
29// TODO: last sdk 3.1.0 and sdk 3.0.3 has MTAPMAN module version 0x03,0x10
30// Check what was changed, and maybe port changes.
31// Note: currently is based on the last XMTAPMAN from BOOTROM:
32// 0x02,0x02
33IRX_ID("multitap_manager", 2, 2);
34
35static s32 event_flag;
36static s32 threadid_main;
37
38static u32 state_open[4];
39static u32 state_getcon[4];
40static u32 state_slots[4];
41static u8 in_buffer[256];
42static u8 out_buffer[256];
43static sio2_transfer_data_t td;
44
45s32 read_stat6c_bit(u32 bit, sio2_transfer_data_t *tdata)
46{
47 switch(bit)
48 {
49 case 0: return (tdata->stat6c >> 16) & 1;
50 case 1: return (tdata->stat6c >> 17) & 1;
51 case 2: return (tdata->stat6c >> 18) & 1;
52 case 3: return (tdata->stat6c >> 19) & 1;
53 case 4: return (tdata->stat6c >> 20) & 1;
54 case 5: return (tdata->stat6c >> 21) & 1;
55 case 6: return (tdata->stat6c >> 22) & 1;
56 case 7: return (tdata->stat6c >> 23) & 1;
57 case 8: return (tdata->stat6c >> 24) & 1;
58 case 9: return (tdata->stat6c >> 25) & 1;
59 case 10: return (tdata->stat6c >> 26) & 1;
60 case 11: return (tdata->stat6c >> 27) & 1;
61 case 12: return (tdata->stat6c >> 28) & 1;
62 case 13: return (tdata->stat6c >> 29) & 1;
63 case 14: return (tdata->stat6c >> 30) & 1;
64 case 15: return (tdata->stat6c >> 31) & 1;
65 default: return 0;
66 }
67}
68
69void get_slot_number_setup_td(u32 port, u32 reg)
70{
71 u32 p = port | 0x2;
72 u32 i;
73
74 td.port_ctrl1[p] = 0xFF020505;
75 td.port_ctrl2[p] = 0x00030064;
76
77 td.regdata[reg] = (p & 0x3) | 0x180640;
78
79 for(i=0; i < 6 ; i++) td.in[td.in_size + i] = 0;
80
81 td.in[td.in_size] = 0x21;
82
83 if(port < 2)
84 td.in[td.in_size + 1] = 0x12;
85 else
86 td.in[td.in_size + 1] = 0x13;
87
88 td.in_size += 6;
89 td.out_size += 6;
90 td.in_dma.addr = 0;
91 td.out_dma.addr = 0;
92}
93
94s32 get_slot_number_check_td(u32 bit)
95{
96 s32 res;
97 u32 i;
98
99 if(read_stat6c_bit(bit, &td) != 1)
100 {
101 if(td.out[5] == 0x66)
102 res = -2;
103 else
104 res = td.out[3];
105 }
106 else
107 {
108 res = -1;
109 }
110
111 for(i=0; i < 250; i++) td.out[i] = td.out[i+6];
112
113 td.out_size -= 6;
114
115 return res;
116}
117s32 get_slot_number(u32 port, u32 retries)
118{
119 u32 i,j;
120 s32 slots = -1;
121
122 if(port >= 4) return -3;
123
124 if(state_open[port] == 0) return -4;
125
126 i = 0;
127
128 while((slots < 0) && (i <= retries))
129 {
130 sio2_mtap_transfer_init();
131
132 td.in_size = 0;
133 td.out_size = 0;
134
135 for(j=0; j < 16; j++) td.regdata[j] = 0;
136
137 get_slot_number_setup_td(port, 0);
138 sio2_transfer2(&td);
139 slots = get_slot_number_check_td(0);
140
141 sio2_transfer_reset2();
142
143 if((slots == -2) || (slots >= 0)) return slots;
144
145 i++;
146 //M_PRINTF("get_slot_number retry %i.\n", (int)i);
147 }
148
149 return -4;
150}
151
152
153void update_slot_numbers_thread(void *arg)
154{
155 (void)arg;
156
157 while(1)
158 {
159 u32 resbits, port;
160 s32 slots;
161
162 WaitEventFlag(event_flag, EF_UPDATE_SLOTS | EF_EXIT_THREAD, 0x11, &resbits);
163
164 if(resbits & EF_EXIT_THREAD)
165 {
166 SetEventFlag(event_flag, 0x4);
167 ExitThread();
168 }
169
170 for(port=0; port < 4; port++)
171 {
172 if(state_open[port] == 1)
173 {
174 if(state_getcon[port] == 0)
175 slots = get_slot_number(port, 10);
176 else
177 slots = get_slot_number(port, 0);
178
179 if(slots < 0)
180 {
181 state_slots[port] = 1;
182 state_getcon[port] = 0;
183 }
184 else
185 {
186 state_slots[port] = slots;
187 state_getcon[port] = 1;
188 }
189 }
190 }
191
192
193 }
194}
195
196s32 change_slot_setup_td(u32 port, s32 slot, u32 reg)
197{
198 u32 p = port | 0x2;
199 u32 i;
200
201 td.port_ctrl1[p] = 0xFF020505;
202 td.port_ctrl2[p] = 0x00030064;
203
204 td.regdata[reg] = (p & 0x3) | 0x1c0740;
205
206 for(i=0; i < 7; i++) td.in[td.in_size + i] = 0;
207
208 td.in[td.in_size] = 0x21;
209
210 if(port < 2)
211 {
212 td.in[td.in_size + 1] = 0x21;
213 }
214 else
215 {
216 td.in[td.in_size + 1] = 0x22;
217 }
218
219 td.in[td.in_size + 2] = (u8)slot;
220
221 td.in_size += 7;
222 td.out_size += 7;
223 td.in_dma.addr = 0;
224 td.out_dma.addr = 0;
225
226
227 return 0;
228}
229
230s32 change_slot_check_td(u32 a)
231{
232 u32 i;
233 s32 res;
234
235 if(td.out_size >= 7)
236 {
237 if(read_stat6c_bit(a, &td) != 1)
238 {
239 if(td.out[5] == 0x66)
240 res = -2;
241 else
242 res = td.out[5];
243
244 }
245 else
246 {
247 res = -1;
248 }
249 }
250 else
251 {
252 return -99;
253 }
254
255
256 for(i=0; i < 249; i++)
257 {
258 td.out[i] = td.out[i+7];
259 }
260
261 td.out_size -= 7;
262
263
264 return res;
265}
266
267int change_slot(s32 *arg)
268{
269 u32 loop = 0;
270 u32 count = 4;
271 s32 data[4];
272 u32 i, port;
273
274 while((loop < 10) && (count != 0))
275 {
276 u32 reg = 0;
277 count = 4;
278
279 td.in_size = 0;
280 td.out_size = 0;
281
282 for(i=0; i < 16; i++) td.regdata[i] = 0;
283
284 // Setup transfer data
285 for(port=0; port < 4; port++)
286 {
287 data[port] = -1;
288
289 if(arg[port] >= 0)
290 {
291 if((state_open[port] == 1) && (state_getcon[port] == 1))
292 {
293 if(state_slots[port] > (u32)(arg[port]))
294 {
295 change_slot_setup_td(port, arg[port], reg);
296
297 data[port] = port;
298 reg++;
299 }
300 else
301 {
302 arg[port+4] = -1;
303 }
304
305 }
306 else
307 {
308 if(arg[port] == 0)
309 arg[port+4] = 1;
310 else
311 arg[port+4] = -1;
312 }
313 }
314 else
315 {
316 arg[port+4] = 0;
317 }
318
319 }
320
321 // Send transfer data and check result
322 if(reg > 0)
323 {
324 sio2_transfer2(&td);
325
326 for(port=0; port < 4; port++)
327 {
328 if(data[port] >= 0)
329 {
330 s32 res = change_slot_check_td(data[port]);
331
332 if(res == -2)
333 {
334 arg[port+4] = -1;
335 count--;
336 }
337 else
338 {
339 if(res >= 0)
340 {
341 if(res == arg[port])
342 arg[port+4] = 1;
343 else
344 arg[port+4] = -1;
345
346 count--;
347 }
348 }
349 }
350 else
351 {
352 count--;
353 }
354 }
355 }
356
357 if(count != 0) loop++;
358 }
359
360 for(i=0; i < 4; i++)
361 {
362 if(arg[i+4] < 0)
363 return 0;
364 }
365
366 return 1;
367
368}
369
370int get_slots1(int port)
371{
372 return state_slots[port];
373}
374
375int get_slots2(int port)
376{
377 return state_slots[port];
378}
379
380void update_slot_numbers()
381{
382 SetEventFlag(event_flag, EF_UPDATE_SLOTS);
383}
384
385int _start(int argc, char *argv[])
386{
389 u32 i;
390
391 (void)argc;
392 (void)argv;
393
394 printf(BANNER,VERSION);
395
396 if(RegisterLibraryEntries(&_exp_mtapman) != 0)
397 {
398 M_PRINTF("RegisterLibraryEntries failed.\n");
399 return MODULE_NO_RESIDENT_END;
400 }
401
402 if(InitRpcServers() == 0)
403 {
404 M_PRINTF("Failed to setup RPC Servers.\n");
405 return MODULE_NO_RESIDENT_END;
406 }
407
408 event.attr = 2;
409 event.bits = 0;
410
411 event_flag = CreateEventFlag(&event);
412
413 if(event_flag < 0)
414 {
415 M_PRINTF("Could not create event flag (%i)\n.", (int)event_flag);
416 return MODULE_NO_RESIDENT_END;
417 }
418
419 thread.attr = TH_C;
420 thread.thread = update_slot_numbers_thread;
421 thread.stacksize = 0x800;
422 thread.priority = 32;
423
424 threadid_main = CreateThread(&thread);
425
426 if(threadid_main < 0)
427 {
428 M_PRINTF("Could not create thread (%i)\n.", (int)threadid_main);
429 return MODULE_NO_RESIDENT_END;
430 }
431
432 StartThread(threadid_main, 0);
433
434 for(i=0; i < 4; i++)
435 {
436 state_open[i] = 0;
437 state_getcon[i] = 0;
438 state_slots[i] = 0;
439 }
440
441 sio2_mtap_change_slot_set(change_slot);
442 sio2_mtap_get_slot_max_set(get_slots1);
443 sio2_mtap_get_slot_max2_set(get_slots2);
444 sio2_mtap_update_slots_set(update_slot_numbers);
445
446 td.in = in_buffer;
447 td.out = out_buffer;
448
449 return MODULE_RESIDENT_END;
450}
451
452
454{
455 u32 i;
456
457 sio2_mtap_change_slot_set(NULL);
458 sio2_mtap_get_slot_max_set(NULL);
459 sio2_mtap_get_slot_max2_set(NULL);
460 sio2_mtap_update_slots_set(NULL);
461
462 for(i=0; i < 4; i++)
463 {
464 state_open[i] = 0;
465 state_getcon[i] = 0;
466 state_slots[i] = 0;
467 }
468}
469
470s32 mtapPortOpen(u32 port)
471{
472 if(port < 4)
473 {
474 state_open[port] = 1;
475
476 s32 res = get_slot_number(port, 10);
477
478 if(res < 0)
479 {
480 state_getcon[port] = 0;
481 state_slots[port] = 1;
482 return res;
483 }
484 else
485 {
486 state_getcon[port] = 1;
487 state_slots[port] = res;
488 return 1;
489 }
490 }
491
492 return 0;
493}
494
495s32 mtapPortClose(u32 port)
496{
497 state_open[port] = 0;
498 state_getcon[port] = 0;
499
500 return 1;
501}
502
503s32 mtapGetConnection(u32 port)
504{
505 return state_getcon[port];
506}
507
508s32 mtapGetSlotNumber(u32 port)
509{
510 s32 res;
511
512 if(port >= 4) return -1;
513
514 if(state_open[port] == 0) return 1;
515
516 res = get_slot_number(port, 10);
517
518 if(res >= 0)
519 return res;
520 else
521 return 1;
522}
523
524s32 mtapChangeSlot(u32 port, u32 slot)
525{
526 s32 data[4];
527 u32 i;
528
529 if(port >= 4) return 0;
530
531 if(state_open[port] == 0)
532 {
533 M_PRINTF("mtap manager doesn't work\n");
534 return -1;
535 }
536
537 for(i=0; i < 4; i++)
538 data[i] = -1;
539
540 data[port] = slot;
541
542 sio2_mtap_transfer_init();
543
544 change_slot(data);
545
546 sio2_transfer_reset2();
547
548 if(data[port] < 0)
549 {
550 M_PRINTF("Failed to change slot.\n");
551 return data[port];
552 }
553 else
554 {
555 M_PRINTF("Change slot complete.\n");
556 return 1;
557 }
558}
559
560
561
void shutdown()
Definition freemtap.c:453
int mtapGetConnection(int port)
Definition libmtap.c:87
int mtapPortClose(int port)
Definition libmtap.c:77
int mtapPortOpen(int port)
Definition libmtap.c:67
u32 count
start sector of fragmented bd/file