PS2SDK
PS2 Homebrew Libraries
sio2man.c
Go to the documentation of this file.
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 
11 #include "irx_imports.h"
12 
18 #include <iop_mmio_hwport.h>
19 #include <rsio2man.h>
20 
21 #ifdef SIO2LOG
22 #include "log.h"
23 #endif
24 
25 #ifdef SIO2LOG
26 IRX_ID("sio2man_logger", 3, 17);
27 #else
28 IRX_ID("sio2man", 3, 17);
29 #endif
30 // Based on the module from SDK 3.1.0.
31 
32 extern struct irx_export_table _exp_sio2man;
33 extern struct irx_export_table _exp_sio2man1;
34 
35 // Unofficial: remove unused structure members
37 {
38  // Unofficial: move inited into bss section
39  int m_inited;
40  int m_intr_sema;
41  int m_transfer_semaphore;
42  // Unofficial: backwards compatibility for libraries using 1.3 SDK
43  int m_sdk13x_curflag;
44  int m_sdk13x_totalflag;
45  sio2_mtap_change_slot_cb_t m_mtap_change_slot_cb;
46  sio2_mtap_get_slot_max_cb_t m_mtap_get_slot_max_cb;
47  sio2_mtap_get_slot_max2_cb_t m_mtap_get_slot_max2_cb;
48  sio2_mtap_update_slots_t m_mtap_update_slots_cb;
49 };
50 
51 #define EPRINTF(format, args...) printf("%s: " format, _irx_id.n, ##args)
52 
53 static struct sio2man_internal_data g_sio2man_data;
54 
55 #ifdef SIO2MAN_NANO
56 #define sio2_ctrl_set inl_sio2_ctrl_set
57 #define sio2_ctrl_get inl_sio2_ctrl_get
58 #define sio2_stat6c_get inl_sio2_stat6c_get
59 #define sio2_portN_ctrl1_set inl_sio2_portN_ctrl1_set
60 #define sio2_portN_ctrl2_set inl_sio2_portN_ctrl2_set
61 #define sio2_regN_set inl_sio2_regN_set
62 #define sio2_stat74_get inl_sio2_stat74_get
63 #define sio2_data_out inl_sio2_data_out
64 #define sio2_data_in inl_sio2_data_in
65 #define sio2_stat_set inl_sio2_stat_set
66 #define sio2_stat_get inl_sio2_stat_get
67 #define sio2_set_ctrl_c inl_sio2_set_ctrl_c
68 #define sio2_set_ctrl_1 inl_sio2_set_ctrl_1
69 #define NANO_STATIC static inline
70 #else
71 #define NANO_STATIC
72 #endif
73 
74 NANO_STATIC void sio2_ctrl_set(u32 val)
75 {
76  USE_IOP_MMIO_HWPORT();
77 
78  iop_mmio_hwport->sio2.ctrl = val;
79 }
80 
81 NANO_STATIC u32 sio2_ctrl_get(void)
82 {
83  USE_IOP_MMIO_HWPORT();
84 
85  return iop_mmio_hwport->sio2.ctrl;
86 }
87 
88 NANO_STATIC u32 sio2_stat6c_get(void)
89 {
90  USE_IOP_MMIO_HWPORT();
91 
92  return iop_mmio_hwport->sio2.recv1;
93 }
94 
95 NANO_STATIC void sio2_portN_ctrl1_set(int N, u32 val)
96 {
97  USE_IOP_MMIO_HWPORT();
98 
99  iop_mmio_hwport->sio2.send1_2_buf[N * 2] = val;
100 }
101 
102 #ifndef SIO2MAN_NANO
103 u32 sio2_portN_ctrl1_get(int N)
104 {
105  USE_IOP_MMIO_HWPORT();
106 
107  return iop_mmio_hwport->sio2.send1_2_buf[N * 2];
108 }
109 #endif
110 
111 NANO_STATIC void sio2_portN_ctrl2_set(int N, u32 val)
112 {
113  USE_IOP_MMIO_HWPORT();
114 
115  iop_mmio_hwport->sio2.send1_2_buf[(N * 2) + 1] = val;
116 }
117 
118 #ifndef SIO2MAN_NANO
119 u32 sio2_portN_ctrl2_get(int N)
120 {
121  USE_IOP_MMIO_HWPORT();
122 
123  return iop_mmio_hwport->sio2.send1_2_buf[(N * 2) + 1];
124 }
125 #endif
126 
127 u32 sio2_stat70_get(void)
128 {
129  USE_IOP_MMIO_HWPORT();
130 
131  return iop_mmio_hwport->sio2.recv2;
132 }
133 
134 NANO_STATIC void sio2_regN_set(int N, u32 val)
135 {
136  USE_IOP_MMIO_HWPORT();
137 
138  iop_mmio_hwport->sio2.send3_buf[N] = val;
139 }
140 
141 #ifndef SIO2MAN_NANO
142 u32 sio2_regN_get(int N)
143 {
144  USE_IOP_MMIO_HWPORT();
145 
146  return iop_mmio_hwport->sio2.send3_buf[N];
147 }
148 #endif
149 
150 NANO_STATIC u32 sio2_stat74_get(void)
151 {
152  USE_IOP_MMIO_HWPORT();
153 
154  return iop_mmio_hwport->sio2.recv3;
155 }
156 
157 #ifndef SIO2MAN_NANO
158 void sio2_unkn78_set(u32 val)
159 {
160  USE_IOP_MMIO_HWPORT();
161 
162  iop_mmio_hwport->sio2.unk_78 = val;
163 }
164 #endif
165 
166 #ifndef SIO2MAN_NANO
167 u32 sio2_unkn78_get(void)
168 {
169  USE_IOP_MMIO_HWPORT();
170 
171  return iop_mmio_hwport->sio2.unk_78;
172 }
173 #endif
174 
175 #ifndef SIO2MAN_NANO
176 void sio2_unkn7c_set(u32 val)
177 {
178  USE_IOP_MMIO_HWPORT();
179 
180  iop_mmio_hwport->sio2.unk_7c = val;
181 }
182 #endif
183 
184 #ifndef SIO2MAN_NANO
185 u32 sio2_unkn7c_get(void)
186 {
187  USE_IOP_MMIO_HWPORT();
188 
189  return iop_mmio_hwport->sio2.unk_7c;
190 }
191 #endif
192 
193 NANO_STATIC void sio2_data_out(u8 val)
194 {
195  USE_IOP_MMIO_HWPORT();
196 
197  iop_mmio_hwport->sio2.out_fifo = val;
198 }
199 
200 NANO_STATIC u8 sio2_data_in(void)
201 {
202  USE_IOP_MMIO_HWPORT();
203 
204  return iop_mmio_hwport->sio2.in_fifo;
205 }
206 
207 NANO_STATIC void sio2_stat_set(u32 val)
208 {
209  USE_IOP_MMIO_HWPORT();
210 
211  iop_mmio_hwport->sio2.stat = val;
212 }
213 
214 NANO_STATIC u32 sio2_stat_get(void)
215 {
216  USE_IOP_MMIO_HWPORT();
217 
218  return iop_mmio_hwport->sio2.stat;
219 }
220 
221 static void send_td(sio2_transfer_data_t *td)
222 {
223  int i;
224 
225 #ifdef SIO2LOG
226  log_default(LOG_TRS);
227 #endif
228 
229  for ( i = 0; i < 4; i += 1 )
230  {
231  sio2_portN_ctrl1_set(i, td->port_ctrl1[i]);
232  sio2_portN_ctrl2_set(i, td->port_ctrl2[i]);
233  }
234 
235 #ifdef SIO2LOG
236  log_portdata(td->port_ctrl1, td->port_ctrl2);
237 #endif
238 
239  for ( i = 0; i < 16; i += 1 )
240  sio2_regN_set(i, td->regdata[i]);
241 
242 #ifdef SIO2LOG
243  log_regdata(td->regdata);
244 #endif
245 
246  for ( i = 0; i < (int)td->in_size; i += 1 )
247  sio2_data_out(td->in[i]);
248 #ifdef SIO2LOG
249  if ( td->in_size )
250  log_data(LOG_TRS_DATA, td->in, td->in_size);
251 #endif
252  if ( td->in_dma.addr )
253  {
254  sceSetSliceDMA(IOP_DMAC_SIO2in, td->in_dma.addr, td->in_dma.size, td->in_dma.count, DMAC_FROM_MEM);
255  sceStartDMA(IOP_DMAC_SIO2in);
256 #ifdef SIO2LOG
257  log_dma(LOG_TRS_DMA_IN, &td->in_dma);
258 #endif
259  }
260  if ( td->out_dma.addr )
261  {
262  sceSetSliceDMA(IOP_DMAC_SIO2out, td->out_dma.addr, td->out_dma.size, td->out_dma.count, DMAC_TO_MEM);
263  sceStartDMA(IOP_DMAC_SIO2out);
264 #ifdef SIO2LOG
265  log_dma(LOG_TRS_DMA_OUT, &td->out_dma);
266 #endif
267  }
268 }
269 
270 static void recv_td(sio2_transfer_data_t *td)
271 {
272  int i;
273 
274 #ifdef SIO2LOG
275  log_default(LOG_TRR);
276 #endif
277  td->stat6c = sio2_stat6c_get();
278  td->stat70 = sio2_stat70_get();
279  td->stat74 = sio2_stat74_get();
280 #ifdef SIO2LOG
281  log_stat(td->stat6c, td->stat70, td->stat74);
282 #endif
283  for ( i = 0; i < (int)td->out_size; i += 1 )
284  td->out[i] = sio2_data_in();
285 #ifdef SIO2LOG
286  if ( td->out_size )
287  log_data(LOG_TRR_DATA, td->out, td->out_size);
288 #endif
289 }
290 
291 static int sio2_intr_handler(void *userdata)
292 {
293  const struct sio2man_internal_data *arg;
294 
295  arg = (const struct sio2man_internal_data *)userdata;
296  sio2_stat_set(sio2_stat_get());
297  iSignalSema(arg->m_intr_sema);
298  return 1;
299 }
300 
301 int _start(int ac, char **av)
302 {
303  iop_sema_t semaparam;
304  int state;
305 
306  (void)ac;
307  (void)av;
308 
309  if ( RegisterLibraryEntries(&_exp_sio2man) != 0 )
310  return 1;
311  // Unofficial: register same name but older major version for backwards compatibility
312  _exp_sio2man1.name[7] = '\x00';
313  if ( RegisterLibraryEntries(&_exp_sio2man1) != 0 )
314  return 1;
315  if ( g_sio2man_data.m_inited )
316  return 1;
317  g_sio2man_data.m_inited = 1;
318  g_sio2man_data.m_sdk13x_curflag = 0;
319  g_sio2man_data.m_sdk13x_totalflag = 3;
320  // Unofficial: remove unneeded thread priority argument handler
321  // Unofficial: use setters instead of setting variable directly
322  sio2_mtap_change_slot_set(NULL);
323  sio2_mtap_get_slot_max_set(NULL);
324  sio2_mtap_get_slot_max2_set(NULL);
325  sio2_mtap_update_slots_set(NULL);
326  // Unofficial: inlined
327  sio2_ctrl_set(0x3BC);
328  CpuSuspendIntr(&state);
329  RegisterIntrHandler(IOP_IRQ_SIO2, 1, sio2_intr_handler, &g_sio2man_data);
330  EnableIntr(IOP_IRQ_SIO2);
331  CpuResumeIntr(state);
332  sceSetDMAPriority(IOP_DMAC_SIO2in, 3);
333  sceSetDMAPriority(IOP_DMAC_SIO2out, 3);
334  sceEnableDMAChannel(IOP_DMAC_SIO2in);
335  sceEnableDMAChannel(IOP_DMAC_SIO2out);
336  semaparam.attr = 0;
337  semaparam.option = 0;
338  semaparam.initial = 1;
339  semaparam.max = 64;
340  g_sio2man_data.m_transfer_semaphore = CreateSema(&semaparam);
341  semaparam.attr = 0;
342  semaparam.option = 0;
343  semaparam.initial = 0;
344  semaparam.max = 64;
345  g_sio2man_data.m_intr_sema = CreateSema(&semaparam);
346 #ifdef SIO2LOG
347  EPRINTF("Logging started.\n");
348 #endif
349  return 0;
350 }
351 
352 void _deinit()
353 {
354  int state;
355 
356  // Unofficial: check inited
357  if ( !g_sio2man_data.m_inited )
358  return;
359 #ifdef SIO2LOG
360  log_flush(1);
361 #endif
362  // Unofficial: unset inited
363  g_sio2man_data.m_inited = 0;
364  // Unofficial: remove unused GetThreadId
365  CpuSuspendIntr(&state);
366  DisableIntr(IOP_IRQ_SIO2, 0);
367  ReleaseIntrHandler(IOP_IRQ_SIO2);
368  CpuResumeIntr(state);
369  sceDisableDMAChannel(IOP_DMAC_SIO2in);
370  sceDisableDMAChannel(IOP_DMAC_SIO2out);
371  DeleteSema(g_sio2man_data.m_intr_sema);
372  DeleteSema(g_sio2man_data.m_transfer_semaphore);
373 }
374 
375 #ifndef SIO2MAN_NANO
376 void sio2_set_intr_handler(int (*handler)(void *userdata), void *userdata)
377 {
378  int state;
379 
380  CpuSuspendIntr(&state);
381  DisableIntr(IOP_IRQ_SIO2, 0);
382  ReleaseIntrHandler(IOP_IRQ_SIO2);
384  IOP_IRQ_SIO2, 1, handler ? handler : sio2_intr_handler, handler ? userdata : &g_sio2man_data);
385  EnableIntr(IOP_IRQ_SIO2);
386  CpuResumeIntr(state);
387 }
388 #endif
389 
390 NANO_STATIC void sio2_set_ctrl_c()
391 {
392  // Unofficial: inlined
393  sio2_ctrl_set(sio2_ctrl_get() | 0xC);
394 }
395 
396 NANO_STATIC void sio2_set_ctrl_1()
397 {
398  // Unofficial: inlined
399  sio2_ctrl_set(sio2_ctrl_get() | 1);
400 }
401 
402 void sio2_wait_for_intr()
403 {
404  WaitSema(g_sio2man_data.m_intr_sema);
405 }
406 
407 int sio2_transfer(sio2_transfer_data_t *td)
408 {
409  // Unofficial: remove unused transfer data global
410  // Unofficial: replace with inlined func
411  sio2_set_ctrl_c();
412  send_td(td);
413  // Unofficial: replace with inlined func
414  sio2_set_ctrl_1();
415  sio2_wait_for_intr();
416  recv_td(td);
417  if ( g_sio2man_data.m_sdk13x_curflag )
418  sio2_transfer_reset();
419 #ifdef SIO2LOG
420  log_flush(0);
421 #endif
422  return 1;
423 }
424 
425 void sio2_pad_transfer_init(void)
426 {
427 #ifdef SIO2LOG
428  log_flush(0);
429 #endif
430  WaitSema(g_sio2man_data.m_transfer_semaphore);
431 #ifdef SIO2LOG
432  log_default(LOG_PAD_READY);
433 #endif
434  g_sio2man_data.m_sdk13x_curflag = 0;
435 }
436 
437 void sio2_pad_transfer_init_possiblysdk13x(void)
438 {
439  sio2_pad_transfer_init();
440  g_sio2man_data.m_sdk13x_curflag |= g_sio2man_data.m_sdk13x_totalflag & 1;
441 }
442 
443 void sio2_mc_transfer_init_possiblysdk13x(void)
444 {
445  sio2_pad_transfer_init();
446  g_sio2man_data.m_sdk13x_curflag |= g_sio2man_data.m_sdk13x_totalflag & 2;
447 }
448 
449 void sio2_transfer_reset(void)
450 {
451  g_sio2man_data.m_sdk13x_curflag = 0;
452  SignalSema(g_sio2man_data.m_transfer_semaphore);
453 #ifdef SIO2LOG
454  log_default(LOG_RESET);
455 #endif
456 }
457 
458 static int sio2_mtap_change_slot_default(s32 *arg)
459 {
460  int sum;
461  int i;
462 
463  sum = 0;
464  for ( i = 0; i < 4; i += 1 )
465  {
466  arg[i + 4] = ((arg[i] + 1) < 2);
467  sum += arg[i + 4];
468  }
469  return sum == 4;
470 }
471 
472 static int sio2_mtap_get_slot_max_default(int port)
473 {
474  return 1;
475 }
476 
477 static void sio2_mtap_update_slots_default(void) {}
478 
479 void sio2_mtap_change_slot_set(sio2_mtap_change_slot_cb_t cb)
480 {
481  // Unofficial: use default callback if NULL
482  g_sio2man_data.m_mtap_change_slot_cb = cb ? cb : sio2_mtap_change_slot_default;
483 }
484 
485 void sio2_mtap_get_slot_max_set(sio2_mtap_get_slot_max_cb_t cb)
486 {
487  // Unofficial: use default callback if NULL
488  g_sio2man_data.m_mtap_get_slot_max_cb = cb ? cb : sio2_mtap_get_slot_max_default;
489 }
490 
491 void sio2_mtap_get_slot_max2_set(sio2_mtap_get_slot_max2_cb_t cb)
492 {
493  // Unofficial: use default callback if NULL
494  g_sio2man_data.m_mtap_get_slot_max2_cb = cb ? cb : sio2_mtap_get_slot_max_default;
495 }
496 
497 void sio2_mtap_update_slots_set(sio2_mtap_update_slots_t cb)
498 {
499  // Unofficial: use default callback if NULL
500  g_sio2man_data.m_mtap_update_slots_cb = cb ? cb : sio2_mtap_update_slots_default;
501 }
502 
503 int sio2_mtap_change_slot(s32 *arg)
504 {
505  g_sio2man_data.m_sdk13x_curflag &= ~g_sio2man_data.m_sdk13x_totalflag;
506  // Unofficial: unconditionally call callback
507  return g_sio2man_data.m_mtap_change_slot_cb(arg);
508 }
509 
510 int sio2_mtap_get_slot_max(int port)
511 {
512  // Unofficial: unconditionally call callback
513  return g_sio2man_data.m_mtap_get_slot_max_cb(port);
514 }
515 
516 int sio2_mtap_get_slot_max2(int port)
517 {
518  // Unofficial: unconditionally call callback
519  return g_sio2man_data.m_mtap_get_slot_max2_cb(port);
520 }
521 
522 void sio2_mtap_update_slots(void)
523 {
524  // Unofficial: unconditionally call callback
525  g_sio2man_data.m_mtap_update_slots_cb();
526 }
RegisterIntrHandler
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition: intrman.c:115
ReleaseIntrHandler
int ReleaseIntrHandler(int irq)
Definition: intrman.c:157
iop_sema_t
Definition: thsemap.h:38
iop_mmio_hwport.h
DisableIntr
int DisableIntr(int irq, int *res)
Definition: intrman.c:385
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
EnableIntr
int EnableIntr(int irq)
Definition: intrman.c:336
irx_export_table
Definition: irx.h:90
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
rsio2man.h
log.h
sio2_transfer_data_t
Definition: sio2man.h:33
sio2man_internal_data
Definition: sio2man.c:36