PS2SDK
PS2 Homebrew Libraries
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 
21 extern 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
33 IRX_ID("multitap_manager", 2, 2);
34 
35 static s32 event_flag;
36 static s32 threadid_main;
37 
38 static u32 state_open[4];
39 static u32 state_getcon[4];
40 static u32 state_slots[4];
41 static u8 in_buffer[256];
42 static u8 out_buffer[256];
43 static sio2_transfer_data_t td;
44 
45 s32 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 
69 void 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 
94 s32 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 }
117 s32 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 
153 void 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 
196 s32 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 
230 s32 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 
267 int 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 
370 int get_slots1(int port)
371 {
372  return state_slots[port];
373 }
374 
375 int get_slots2(int port)
376 {
377  return state_slots[port];
378 }
379 
380 void update_slot_numbers()
381 {
382  SetEventFlag(event_flag, EF_UPDATE_SLOTS);
383 }
384 
385 int _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 
453 void shutdown()
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 
470 s32 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 
495 s32 mtapPortClose(u32 port)
496 {
497  state_open[port] = 0;
498  state_getcon[port] = 0;
499 
500  return 1;
501 }
502 
503 s32 mtapGetConnection(u32 port)
504 {
505  return state_getcon[port];
506 }
507 
508 s32 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 
524 s32 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 
xsio2man.h
thbase.h
thread
Definition: thcommon.h:143
event
Definition: thcommon.h:71
freemtap.h
loadcore.h
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
irx.h
mtapGetConnection
int mtapGetConnection(int port)
Definition: libmtap.c:91
irx_export_table
Definition: irx.h:90
stdio.h
_iop_thread
Definition: thbase.h:39
sio2_transfer_data_t
Definition: sio2man.h:33
event_flag
Definition: thcommon.h:79
mtapPortOpen
int mtapPortOpen(int port)
Definition: libmtap.c:71
mtapPortClose
int mtapPortClose(int port)
Definition: libmtap.c:81
iop_event_t
Definition: thevent.h:37
thevent.h