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()
154{
155 while(1)
156 {
157 u32 resbits, port;
158 s32 slots;
159
160 WaitEventFlag(event_flag, EF_UPDATE_SLOTS | EF_EXIT_THREAD, 0x11, &resbits);
161
162 if(resbits & EF_EXIT_THREAD)
163 {
164 SetEventFlag(event_flag, 0x4);
165 ExitThread();
166 }
167
168 for(port=0; port < 4; port++)
169 {
170 if(state_open[port] == 1)
171 {
172 if(state_getcon[port] == 0)
173 slots = get_slot_number(port, 10);
174 else
175 slots = get_slot_number(port, 0);
176
177 if(slots < 0)
178 {
179 state_slots[port] = 1;
180 state_getcon[port] = 0;
181 }
182 else
183 {
184 state_slots[port] = slots;
185 state_getcon[port] = 1;
186 }
187 }
188 }
189
190
191 }
192}
193
194s32 change_slot_setup_td(u32 port, s32 slot, u32 reg)
195{
196 u32 p = port | 0x2;
197 u32 i;
198
199 td.port_ctrl1[p] = 0xFF020505;
200 td.port_ctrl2[p] = 0x00030064;
201
202 td.regdata[reg] = (p & 0x3) | 0x1c0740;
203
204 for(i=0; i < 7; i++) td.in[td.in_size + i] = 0;
205
206 td.in[td.in_size] = 0x21;
207
208 if(port < 2)
209 {
210 td.in[td.in_size + 1] = 0x21;
211 }
212 else
213 {
214 td.in[td.in_size + 1] = 0x22;
215 }
216
217 td.in[td.in_size + 2] = (u8)slot;
218
219 td.in_size += 7;
220 td.out_size += 7;
221 td.in_dma.addr = 0;
222 td.out_dma.addr = 0;
223
224
225 return 0;
226}
227
228s32 change_slot_check_td(u32 a)
229{
230 u32 i;
231 s32 res;
232
233 if(td.out_size >= 7)
234 {
235 if(read_stat6c_bit(a, &td) != 1)
236 {
237 if(td.out[5] == 0x66)
238 res = -2;
239 else
240 res = td.out[5];
241
242 }
243 else
244 {
245 res = -1;
246 }
247 }
248 else
249 {
250 return -99;
251 }
252
253
254 for(i=0; i < 249; i++)
255 {
256 td.out[i] = td.out[i+7];
257 }
258
259 td.out_size -= 7;
260
261
262 return res;
263}
264
265int change_slot(s32 *arg)
266{
267 u32 loop = 0;
268 u32 count = 4;
269 s32 data[4];
270 u32 i, port;
271
272 while((loop < 10) && (count != 0))
273 {
274 u32 reg = 0;
275 count = 4;
276
277 td.in_size = 0;
278 td.out_size = 0;
279
280 for(i=0; i < 16; i++) td.regdata[i] = 0;
281
282 // Setup transfer data
283 for(port=0; port < 4; port++)
284 {
285 data[port] = -1;
286
287 if(arg[port] >= 0)
288 {
289 if((state_open[port] == 1) && (state_getcon[port] == 1))
290 {
291 if(state_slots[port] > (u32)(arg[port]))
292 {
293 change_slot_setup_td(port, arg[port], reg);
294
295 data[port] = port;
296 reg++;
297 }
298 else
299 {
300 arg[port+4] = -1;
301 }
302
303 }
304 else
305 {
306 if(arg[port] == 0)
307 arg[port+4] = 1;
308 else
309 arg[port+4] = -1;
310 }
311 }
312 else
313 {
314 arg[port+4] = 0;
315 }
316
317 }
318
319 // Send transfer data and check result
320 if(reg > 0)
321 {
322 sio2_transfer2(&td);
323
324 for(port=0; port < 4; port++)
325 {
326 if(data[port] >= 0)
327 {
328 s32 res = change_slot_check_td(data[port]);
329
330 if(res == -2)
331 {
332 arg[port+4] = -1;
333 count--;
334 }
335 else
336 {
337 if(res >= 0)
338 {
339 if(res == arg[port])
340 arg[port+4] = 1;
341 else
342 arg[port+4] = -1;
343
344 count--;
345 }
346 }
347 }
348 else
349 {
350 count--;
351 }
352 }
353 }
354
355 if(count != 0) loop++;
356 }
357
358 for(i=0; i < 4; i++)
359 {
360 if(arg[i+4] < 0)
361 return 0;
362 }
363
364 return 1;
365
366}
367
368int get_slots1(int port)
369{
370 return state_slots[port];
371}
372
373int get_slots2(int port)
374{
375 return state_slots[port];
376}
377
378void update_slot_numbers()
379{
380 SetEventFlag(event_flag, EF_UPDATE_SLOTS);
381}
382
383int _start(int argc, char *argv[])
384{
387 u32 i;
388
389 (void)argc;
390 (void)argv;
391
392 printf(BANNER,VERSION);
393
394 if(RegisterLibraryEntries(&_exp_mtapman) != 0)
395 {
396 M_PRINTF("RegisterLibraryEntries failed.\n");
397 return MODULE_NO_RESIDENT_END;
398 }
399
400 if(InitRpcServers() == 0)
401 {
402 M_PRINTF("Failed to setup RPC Servers.\n");
403 return MODULE_NO_RESIDENT_END;
404 }
405
406 event.attr = 2;
407 event.bits = 0;
408
409 event_flag = CreateEventFlag(&event);
410
411 if(event_flag < 0)
412 {
413 M_PRINTF("Could not create event flag (%i)\n.", (int)event_flag);
414 return MODULE_NO_RESIDENT_END;
415 }
416
417 thread.attr = TH_C;
418 thread.thread = update_slot_numbers_thread;
419 thread.stacksize = 0x800;
420 thread.priority = 32;
421
422 threadid_main = CreateThread(&thread);
423
424 if(threadid_main < 0)
425 {
426 M_PRINTF("Could not create thread (%i)\n.", (int)threadid_main);
427 return MODULE_NO_RESIDENT_END;
428 }
429
430 StartThread(threadid_main, 0);
431
432 for(i=0; i < 4; i++)
433 {
434 state_open[i] = 0;
435 state_getcon[i] = 0;
436 state_slots[i] = 0;
437 }
438
439 sio2_mtap_change_slot_set(change_slot);
440 sio2_mtap_get_slot_max_set(get_slots1);
441 sio2_mtap_get_slot_max2_set(get_slots2);
442 sio2_mtap_update_slots_set(update_slot_numbers);
443
444 td.in = in_buffer;
445 td.out = out_buffer;
446
447 return MODULE_RESIDENT_END;
448}
449
450
452{
453 u32 i;
454
455 sio2_mtap_change_slot_set(NULL);
456 sio2_mtap_get_slot_max_set(NULL);
457 sio2_mtap_get_slot_max2_set(NULL);
458 sio2_mtap_update_slots_set(NULL);
459
460 for(i=0; i < 4; i++)
461 {
462 state_open[i] = 0;
463 state_getcon[i] = 0;
464 state_slots[i] = 0;
465 }
466}
467
468s32 mtapPortOpen(u32 port)
469{
470 if(port < 4)
471 {
472 state_open[port] = 1;
473
474 s32 res = get_slot_number(port, 10);
475
476 if(res < 0)
477 {
478 state_getcon[port] = 0;
479 state_slots[port] = 1;
480 return res;
481 }
482 else
483 {
484 state_getcon[port] = 1;
485 state_slots[port] = res;
486 return 1;
487 }
488 }
489
490 return 0;
491}
492
493s32 mtapPortClose(u32 port)
494{
495 state_open[port] = 0;
496 state_getcon[port] = 0;
497
498 return 1;
499}
500
501s32 mtapGetConnection(u32 port)
502{
503 return state_getcon[port];
504}
505
506s32 mtapGetSlotNumber(u32 port)
507{
508 s32 res;
509
510 if(port >= 4) return -1;
511
512 if(state_open[port] == 0) return 1;
513
514 res = get_slot_number(port, 10);
515
516 if(res >= 0)
517 return res;
518 else
519 return 1;
520}
521
522s32 mtapChangeSlot(u32 port, u32 slot)
523{
524 s32 data[4];
525 u32 i;
526
527 if(port >= 4) return 0;
528
529 if(state_open[port] == 0)
530 {
531 M_PRINTF("mtap manager doesn't work\n");
532 return -1;
533 }
534
535 for(i=0; i < 4; i++)
536 data[i] = -1;
537
538 data[port] = slot;
539
540 sio2_mtap_transfer_init();
541
542 change_slot(data);
543
544 sio2_transfer_reset2();
545
546 if(data[port] < 0)
547 {
548 M_PRINTF("Failed to change slot.\n");
549 return data[port];
550 }
551 else
552 {
553 M_PRINTF("Change slot complete.\n");
554 return 1;
555 }
556}
557
558
559
void shutdown()
Definition freemtap.c:451
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