PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
sio2man.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
16#include <irx.h>
17#include <defs.h>
18#include <types.h>
19
20#include <loadcore.h>
21#include <intrman.h>
22#include <dmacman.h>
23#include <stdio.h>
24#include <thbase.h>
25#include <thevent.h>
26#include <ioman.h>
27
28#include "xsio2man.h"
29
30#ifdef SIO2LOG
31 #include "log.h"
32#endif
33
34// TODO: last sdk 3.1.0 and sdk 3.0.3 has SIO2MAN module version 0x03,0x11
35// Check what was changed, and maybe port changes.
36// Note: currently is based on the last XPADMAN from BOOTROM:
37// 0x02,0x01 (where is 0x02,0x04?)
38#ifdef SIO2LOG
39 IRX_ID("sio2man_logger", 2, 1);
40#else
41#ifdef BUILDING_XSIO2MAN
42#ifdef BUILDING_XSIO2MAN_V2
43 IRX_ID("sio2man", 2, 4);
44#else
45 IRX_ID("sio2man", 2, 1);
46#endif
47#else
48 IRX_ID("sio2man", 1, 1);
49#endif
50#endif
51
52extern struct irx_export_table _exp_sio2man;
53
54#define SIO2_REG_BASE 0xbf808200
55#define SIO2_REG_PORT0_CTRL1 0xbf808240
56#define SIO2_REG_PORT0_CTRL2 0xbf808244
57#define SIO2_REG_DATA_OUT 0xbf808260
58#define SIO2_REG_DATA_IN 0xbf808264
59#define SIO2_REG_CTRL 0xbf808268
60#define SIO2_REG_STAT6C 0xbf80826c
61#define SIO2_REG_STAT70 0xbf808270
62#define SIO2_REG_STAT74 0xbf808274
63#define SIO2_REG_UNKN78 0xbf808278
64#define SIO2_REG_UNKN7C 0xbf80827c
65#define SIO2_REG_STAT 0xbf808280
66
67/* Event flags */
68#define EF_PAD_TRANSFER_INIT 0x00000001
69#define EF_PAD_TRANSFER_READY 0x00000002
70#define EF_MC_TRANSFER_INIT 0x00000004
71#define EF_MC_TRANSFER_READY 0x00000008
72#ifdef BUILDING_XSIO2MAN
73#define EF_MTAP_TRANSFER_INIT 0x00000010
74#define EF_MTAP_TRANSFER_READY 0x00000020
75#ifdef BUILDING_XSIO2MAN_V2
76 #define EF_RM_TRANSFER_INIT 0x00000040
77 #define EF_RM_TRANSFER_READY 0x00000080
78 #define EF_UNK_TRANSFER_INIT 0x00000100
79 #define EF_UNK_TRANSFER_READY 0x00000200
80 #define EF_TRANSFER_START 0x00000400
81 #define EF_TRANSFER_FINISH 0x00000800
82 #define EF_TRANSFER_RESET 0x00001000
83 #define EF_SIO2_INTR_COMPLETE 0x00002000
84#else
85 #define EF_TRANSFER_START 0x00000040
86 #define EF_TRANSFER_FINISH 0x00000080
87 #define EF_TRANSFER_RESET 0x00000100
88 #define EF_SIO2_INTR_COMPLETE 0x00000200
89#endif
90#else
91 #define EF_TRANSFER_START 0x00000010
92 #define EF_TRANSFER_FINISH 0x00000020
93 #define EF_TRANSFER_RESET 0x00000040
94 #define EF_SIO2_INTR_COMPLETE 0x00000080
95#endif
96
97#define EPRINTF(format, args...) printf("%s: " format, _irx_id.n , ## args)
98
99int init = 0;
100int event_flag = -1;
101int thid = -1;
102sio2_transfer_data_t *transfer_data = NULL;
103int (*mtap_change_slot_cb)(s32 *) = NULL;
104int (*mtap_get_slot_max_cb)(int) = NULL;
105int (*mtap_get_slot_max2_cb)(int) = NULL;
106void (*mtap_update_slots_cb)(void) = NULL;
107
108int sio2_intr_handler(void *arg)
109{
110 int ef = *(int *)arg;
111
112 sio2_stat_set(sio2_stat_get());
113
114 iSetEventFlag(ef, EF_SIO2_INTR_COMPLETE);
115
116 return 1;
117}
118
119void send_td(sio2_transfer_data_t *td)
120{
121 int i;
122
123#ifdef SIO2LOG
124 log_default(LOG_TRS);
125#endif
126
127 for (i = 0; i < 4; i++) {
128 sio2_portN_ctrl1_set(i, td->port_ctrl1[i]);
129 sio2_portN_ctrl2_set(i, td->port_ctrl2[i]);
130 }
131
132#ifdef SIO2LOG
133 log_portdata(td->port_ctrl1, td->port_ctrl2);
134#endif
135
136 for (i = 0; i < 16; i++)
137 sio2_regN_set(i, td->regdata[i]);
138
139#ifdef SIO2LOG
140 log_regdata(td->regdata);
141#endif
142
143 if (td->in_size) {
144 for (i = 0; (u32)i < td->in_size; i++)
145 sio2_data_out(td->in[i]);
146#ifdef SIO2LOG
147 log_data(LOG_TRS_DATA, td->in, td->in_size);
148#endif
149 }
150
151 if (td->in_dma.addr) {
152 sceSetSliceDMA(IOP_DMAC_SIO2in, td->in_dma.addr, td->in_dma.size,
153 td->in_dma.count, DMAC_FROM_MEM);
154 sceStartDMA(IOP_DMAC_SIO2in);
155
156#ifdef SIO2LOG
157 log_dma(LOG_TRS_DMA_IN, &td->in_dma);
158#endif
159 }
160
161 if (td->out_dma.addr) {
162 sceSetSliceDMA(IOP_DMAC_SIO2out, td->out_dma.addr, td->out_dma.size,
163 td->out_dma.count, DMAC_TO_MEM);
164 sceStartDMA(IOP_DMAC_SIO2out);
165
166#ifdef SIO2LOG
167 log_dma(LOG_TRS_DMA_OUT, &td->out_dma);
168#endif
169 }
170}
171
172void recv_td(sio2_transfer_data_t *td)
173{
174 int i;
175#ifdef SIO2LOG
176 log_default(LOG_TRR);
177#endif
178 td->stat6c = sio2_stat6c_get();
179 td->stat70 = sio2_stat70_get();
180 td->stat74 = sio2_stat74_get();
181#ifdef SIO2LOG
182 log_stat(td->stat6c, td->stat70, td->stat74);
183#endif
184 if (td->out_size) {
185 for (i = 0; (u32)i < td->out_size; i++)
186 td->out[i] = sio2_data_in();
187#ifdef SIO2LOG
188 log_data(LOG_TRR_DATA, td->out, td->out_size);
189#endif
190 }
191}
192
193void main_thread(void *unused)
194{
195 u32 resbits[4];
196
197 (void)unused;
198
199 while (1) {
200 #ifdef SIO2LOG
201 log_flush(0);
202 #endif
203 WaitEventFlag(event_flag, EF_PAD_TRANSFER_INIT |
204 EF_MC_TRANSFER_INIT
205#ifdef BUILDING_XSIO2MAN
206 | EF_MTAP_TRANSFER_INIT
207#ifdef BUILDING_XSIO2MAN_V2
208 | EF_RM_TRANSFER_INIT | EF_UNK_TRANSFER_INIT
209#endif
210#endif
211 , 1, resbits);
212
213 if (resbits[0] & EF_PAD_TRANSFER_INIT) {
214 ClearEventFlag(event_flag, ~EF_PAD_TRANSFER_INIT);
215 SetEventFlag(event_flag, EF_PAD_TRANSFER_READY);
216#ifdef SIO2LOG
217 log_default(LOG_PAD_READY);
218#endif
219 } else if (resbits[0] & EF_MC_TRANSFER_INIT) {
220 ClearEventFlag(event_flag, ~EF_MC_TRANSFER_INIT);
221 SetEventFlag(event_flag, EF_MC_TRANSFER_READY);
222#ifdef SIO2LOG
223 log_default(LOG_MC_READY);
224#endif
225 }
226#ifdef BUILDING_XSIO2MAN
227 else if (resbits[0] & EF_MTAP_TRANSFER_INIT) {
228 ClearEventFlag(event_flag, ~EF_MTAP_TRANSFER_INIT);
229 SetEventFlag(event_flag, EF_MTAP_TRANSFER_READY);
230#ifdef SIO2LOG
231 log_default(LOG_MTAP_READY);
232#endif
233 }
234#ifdef BUILDING_XSIO2MAN_V2
235 else if (resbits[0] & EF_RM_TRANSFER_INIT) {
236 ClearEventFlag(event_flag, ~EF_RM_TRANSFER_INIT);
237 SetEventFlag(event_flag, EF_RM_TRANSFER_READY);
238#ifdef SIO2LOG
239 log_default(LOG_RM_READY);
240#endif
241 } else if (resbits[0] & EF_UNK_TRANSFER_INIT) {
242 ClearEventFlag(event_flag, ~EF_UNK_TRANSFER_INIT);
243 SetEventFlag(event_flag, EF_UNK_TRANSFER_READY);
244#ifdef SIO2LOG
245 log_default(LOG_UNK_READY);
246#endif
247 }
248#endif
249#endif
250 else {
251#ifdef BUILDING_XSIO2MAN
252 EPRINTF("Unknown event %08lx. Exiting.\n", resbits[0]);
253#else
254 EPRINTF("SIO2_BASIC_THREAD : why I wakeup ? %08lx\n", resbits[0]);
255#endif
256 return;
257 }
258
259#ifdef BUILDING_XSIO2MAN
260transfer_loop:
261#endif
262 WaitEventFlag(event_flag, EF_TRANSFER_START
263#ifdef BUILDING_XSIO2MAN
264 | EF_TRANSFER_RESET
265#endif
266 , 1, resbits);
267
268#ifdef BUILDING_XSIO2MAN
269 if (resbits[0] & EF_TRANSFER_RESET) {
270 ClearEventFlag(event_flag, ~EF_TRANSFER_RESET);
271#ifdef SIO2LOG
272 log_default(LOG_RESET);
273#endif
274 continue;
275 }
276#endif
277
278 ClearEventFlag(event_flag, ~EF_TRANSFER_START);
279
280 sio2_ctrl_set(sio2_ctrl_get() | 0xc);
281 send_td(transfer_data);
282 sio2_ctrl_set(sio2_ctrl_get() | 1);
283
284 WaitEventFlag(event_flag, EF_SIO2_INTR_COMPLETE, 0, NULL);
285 ClearEventFlag(event_flag, ~EF_SIO2_INTR_COMPLETE);
286
287 recv_td(transfer_data);
288 SetEventFlag(event_flag, EF_TRANSFER_FINISH);
289#ifndef BUILDING_XSIO2MAN
290 WaitEventFlag(event_flag, EF_TRANSFER_RESET, 0, NULL);
291 ClearEventFlag(event_flag, ~EF_TRANSFER_RESET);
292#endif
293
294 /* Bah... this is needed to get the initial dump from XMCMAN,
295 but it will kill the IOP when XPADMAN is spamming...
296
297 TODO
298 I guess the correct solution is to do all logging in a
299 dedicated thread. */
300// log_flush(1);
301
302#ifdef BUILDING_XSIO2MAN
303 goto transfer_loop;
304#endif
305 }
306}
307
308int create_main_thread(void)
309{
311
312 thread.attr = 0x2000000;
313 thread.option = 0;
314 thread.thread = main_thread;
315 thread.stacksize = 0x8000;
316 thread.priority = 0x18;
317 return CreateThread(&thread);
318}
319
320int create_event_flag(void)
321{
323
324 event.attr = 2;
325 event.option = 0;
326 event.bits = 0;
327 return CreateEventFlag(&event);
328}
329
330void shutdown(void)
331{
332 int state;
333#ifdef SIO2LOG
334 log_flush(1);
335#endif
336 CpuSuspendIntr(&state);
337 DisableIntr(IOP_IRQ_SIO2, 0);
338 ReleaseIntrHandler(IOP_IRQ_SIO2);
339 CpuResumeIntr(state);
340
341 sceDisableDMAChannel(IOP_DMAC_SIO2in);
342 sceDisableDMAChannel(IOP_DMAC_SIO2out);
343}
344
345int _start(int argc, char *argv[])
346{
347 int state;
348
349 (void)argc;
350 (void)argv;
351
352 shutdown();
353
354 if (RegisterLibraryEntries(&_exp_sio2man) != 0)
355 return MODULE_NO_RESIDENT_END;
356
357 if (init)
358 return MODULE_NO_RESIDENT_END;
359
360 init = 1;
361
362 sio2_ctrl_set(0x3bc);
363
364 mtap_change_slot_cb = NULL; mtap_get_slot_max_cb = NULL; mtap_get_slot_max2_cb = NULL; mtap_update_slots_cb = NULL;
365 event_flag = create_event_flag();
366 thid = create_main_thread();
367
368 CpuSuspendIntr(&state);
369 RegisterIntrHandler(IOP_IRQ_SIO2, 1, sio2_intr_handler, &event_flag);
370 EnableIntr(IOP_IRQ_SIO2);
371 CpuResumeIntr(state);
372
373 sceSetDMAPriority(IOP_DMAC_SIO2in, 3);
374 sceSetDMAPriority(IOP_DMAC_SIO2out, 3);
375 sceEnableDMAChannel(IOP_DMAC_SIO2in);
376 sceEnableDMAChannel(IOP_DMAC_SIO2out);
377
378 StartThread(thid, NULL);
379#ifdef SIO2LOG
380 EPRINTF("Logging started.\n");
381#endif
382 return MODULE_RESIDENT_END;
383}
384
385void sio2_pad_transfer_init(void)
386{
387 SetEventFlag(event_flag, EF_PAD_TRANSFER_INIT);
388
389 WaitEventFlag(event_flag, EF_PAD_TRANSFER_READY, 0, NULL);
390 ClearEventFlag(event_flag, ~EF_PAD_TRANSFER_READY);
391}
392
393void sio2_mc_transfer_init(void)
394{
395 SetEventFlag(event_flag, EF_MC_TRANSFER_INIT);
396
397 WaitEventFlag(event_flag, EF_MC_TRANSFER_READY, 0, NULL);
398 ClearEventFlag(event_flag, ~EF_MC_TRANSFER_READY);
399}
400
401#ifdef BUILDING_XSIO2MAN
402void sio2_mtap_transfer_init(void)
403{
404 SetEventFlag(event_flag, EF_MTAP_TRANSFER_INIT);
405
406 WaitEventFlag(event_flag, EF_MTAP_TRANSFER_READY, 0, NULL);
407 ClearEventFlag(event_flag, ~EF_MTAP_TRANSFER_READY);
408}
409#endif
410
411int sio2_transfer(sio2_transfer_data_t *td)
412{
413 transfer_data = td;
414 SetEventFlag(event_flag, EF_TRANSFER_START);
415
416 WaitEventFlag(event_flag, EF_TRANSFER_FINISH, 0, NULL);
417 ClearEventFlag(event_flag, ~EF_TRANSFER_FINISH);
418
419#ifndef BUILDING_XSIO2MAN
420 SetEventFlag(event_flag, EF_TRANSFER_RESET);
421#endif
422 return 1;
423}
424
425#ifdef BUILDING_XSIO2MAN
426#ifdef BUILDING_XSIO2MAN_V2
427void sio2_rm_transfer_init(void)
428{
429 SetEventFlag(event_flag, EF_RM_TRANSFER_INIT);
430
431 WaitEventFlag(event_flag, EF_RM_TRANSFER_READY, 0, NULL);
432 ClearEventFlag(event_flag, ~EF_RM_TRANSFER_READY);
433}
434
435void sio2_unk_transfer_init(void)
436{
437 SetEventFlag(event_flag, EF_UNK_TRANSFER_INIT);
438
439 WaitEventFlag(event_flag, EF_UNK_TRANSFER_READY, 0, NULL);
440 ClearEventFlag(event_flag, ~EF_UNK_TRANSFER_READY);
441}
442#endif
443#endif
444
445#ifdef BUILDING_XSIO2MAN
446void sio2_transfer_reset(void)
447{
448 SetEventFlag(event_flag, EF_TRANSFER_RESET);
449}
450
451int sio2_mtap_change_slot(s32 *status)
452{
453 int i, ret = 1;
454
455 if (mtap_change_slot_cb)
456 return mtap_change_slot_cb(status);
457
458 for (i = 0; i < 4; i++, status++) {
459 if ((*status + 1) < 2)
460 status[4] = 1;
461 else {
462 status[4] = 0;
463 ret = 0;
464 }
465 }
466
467 return ret;
468}
469
470int sio2_mtap_get_slot_max(int port)
471{
472 if (mtap_get_slot_max_cb)
473 return mtap_get_slot_max_cb(port);
474
475 return 1;
476}
477
478int sio2_mtap_get_slot_max2(int port)
479{
480 if (mtap_get_slot_max2_cb)
481 return mtap_get_slot_max2_cb(port);
482
483 return 1;
484}
485
486void sio2_mtap_update_slots(void)
487{
488 if (mtap_update_slots_cb)
489 mtap_update_slots_cb();
490}
491#endif
492
493#ifdef BUILDING_XSIO2MAN
494void sio2_mtap_change_slot_set(sio2_mtap_change_slot_cb_t cb) { mtap_change_slot_cb = cb; }
495void sio2_mtap_get_slot_max_set(sio2_mtap_get_slot_max_cb_t cb) { mtap_get_slot_max_cb = cb; }
496void sio2_mtap_get_slot_max2_set(sio2_mtap_get_slot_max2_cb_t cb) { mtap_get_slot_max2_cb = cb; }
497void sio2_mtap_update_slots_set(sio2_mtap_update_slots_t cb) { mtap_update_slots_cb = cb; }
498#endif
499
500void sio2_ctrl_set(u32 val) { _sw(val, SIO2_REG_CTRL); }
501u32 sio2_ctrl_get() { return _lw(SIO2_REG_CTRL); }
502u32 sio2_stat6c_get() { return _lw(SIO2_REG_STAT6C); }
503void sio2_portN_ctrl1_set(int N, u32 val) { _sw(val, SIO2_REG_PORT0_CTRL1 + (N * 8)); }
504u32 sio2_portN_ctrl1_get(int N) { return _lw(SIO2_REG_PORT0_CTRL1 + (N * 8)); }
505void sio2_portN_ctrl2_set(int N, u32 val) { _sw(val, SIO2_REG_PORT0_CTRL2 + (N * 8)); }
506u32 sio2_portN_ctrl2_get(int N) { return _lw(SIO2_REG_PORT0_CTRL2 + (N * 8)); }
507u32 sio2_stat70_get() { return _lw(SIO2_REG_STAT70); }
508void sio2_regN_set(int N, u32 val) { _sw(val, SIO2_REG_BASE + (N * 4)); }
509u32 sio2_regN_get(int N) { return _lw(SIO2_REG_BASE + (N * 4)); }
510u32 sio2_stat74_get() { return _lw(SIO2_REG_STAT74); }
511void sio2_unkn78_set(u32 val) { _sw(val, SIO2_REG_UNKN78); }
512u32 sio2_unkn78_get() { return _lw(SIO2_REG_UNKN78); }
513void sio2_unkn7c_set(u32 val) { _sw(val, SIO2_REG_UNKN7C); }
514u32 sio2_unkn7c_get() { return _lw(SIO2_REG_UNKN7C); }
515void sio2_data_out(u8 val) { _sb(val, SIO2_REG_DATA_OUT); }
516u8 sio2_data_in() { return _lb(SIO2_REG_DATA_IN); }
517void sio2_stat_set(u32 val) { _sw(val, SIO2_REG_STAT); }
518u32 sio2_stat_get() { return _lw(SIO2_REG_STAT); }
void shutdown(void)
Definition sio2man.c:330
int CpuResumeIntr(int state)
Definition intrman.c:227
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *), void *arg)
Definition intrman.c:125
int ReleaseIntrHandler(int irq)
Definition intrman.c:167
int DisableIntr(int irq, int *res)
Definition intrman.c:395
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int EnableIntr(int irq)
Definition intrman.c:346