PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
padData.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 "irx.h"
13#include "types.h"
14#include "sio2man.h"
15#ifdef BUILDING_XPADMAN
16#include "xsio2man.h"
17#endif
18#include "sifman.h"
19#include "sio2Cmds.h"
20#include "padData.h"
21#include "stdio.h"
22#include "freepad.h"
23
24typedef struct
25{
26 u32 active;
27 u32 unused_4;
28 u32 unused_8;
29 u32 stat70bit;
30 u32 in_size;
31 u32 out_size;
32 u8 in_buffer[32];
33 u8 out_buffer[32];
34 u32 port_ctrl1;
35 u32 port_ctrl2;
36 u32 reg_data;
37 u32 error;
38} padData_t;
39
40static padData_t padData[2][4];
41
42static sio2_transfer_data_t sio2_td;
43static u8 sio2_in_buffer[256];
44static u8 sio2_out_buffer[256];
45static s32 change_slot_buffer[8];
46
47static int transferCount;
48
49#ifndef BUILDING_XPADMAN
50static int pd_set_change_slot_buffer(s32 *status)
51{
52 int i, ret = 1;
53
54 for (i = 0; i < 4; i++, status++) {
55 if ((*status + 1) < 2)
56 status[4] = 1;
57 else {
58 status[4] = 0;
59 ret = 0;
60 }
61 }
62
63 return ret;
64}
65#endif
66
67u32 pdGetInSize(u8 id)
68{
69 if(id == 0) id = PAD_ID_DIGITAL;
70
71 return (PAD_ID_LO(id)*2)+3;
72}
73
74u32 pdGetOutSize(u8 id)
75{
76 if(id == 0) id = PAD_ID_DIGITAL;
77
78 return (PAD_ID_LO(id)*2)+3;
79}
80
81u32 pdGetRegData(u32 id)
82{
83 u32 ret1, ret2;
84
85 ret1 = pdGetInSize((u8)id);
86
87 ret2 = pdGetOutSize((u8)id);
88
89 return ((ret2 & 0x1FF) << 18) | ((ret1 & 0x1FF) << 8) | 0x40;
90}
91
92u32 pdSetRegData(u32 port, u32 slot, u32 reg_data)
93{
94 if(port < 2)
95 {
96 padData[port][slot].reg_data = reg_data;
97 return 1;
98 }
99
100 return 0;
101
102}
103
104u32 setupReadData(u32 port, u32 slot, u32 val)
105{
106 u32 res;
107 u8 buf[32];
108
109 res = sio2CmdGetPortCtrl1(0, val, 0);
110
111 pdSetCtrl1(port, slot, res);
112
113 res = sio2CmdGetPortCtrl2(0, val);
114
115 pdSetCtrl2(port, slot, res);
116
117
118 res = pdGetRegData(0);
119
120 pdSetRegData(port, slot, res);
121
122
123 res = pdGetInSize(0);
124
125 pdSetInSize(port, slot, res);
126
127 res = pdGetOutSize(0);
128
129 pdSetOutSize(port, slot, res);
130
131 sio2CmdSetReadData(0, buf);
132
133 pdSetInBuffer(port, slot, 0, buf);
134
135 return 1;
136}
137
138u32 pdSetActive(u32 port, u32 slot, u32 active)
139{
140 u32 res = padData[port][slot].active;
141
142 padData[port][slot].active = active;
143
144 return res;
145}
146
147u32 pdIsActive(u32 port, u32 slot)
148{
149 return padData[port][slot].active;
150}
151
152static u32 mtapChangeSlot(u32 slot)
153{
154 change_slot_buffer[0] = -1;
155 change_slot_buffer[1] = -1;
156 change_slot_buffer[2] = -1;
157 change_slot_buffer[3] = -1;
158
159 if( (padData[0][slot].active == 0) && (padData[1][slot].active == 0) )
160 return 0;
161
162 if(padData[0][slot].active == 1)
163 change_slot_buffer[0] = slot;
164
165 if(padData[1][slot].active == 1)
166 change_slot_buffer[1] = slot;
167
168#ifdef BUILDING_XPADMAN
169 sio2_mtap_change_slot(change_slot_buffer);
170#else
171 pd_set_change_slot_buffer(change_slot_buffer);
172#endif
173
174 return 1;
175}
176
177u32 pdSetStat70bit(u32 port, u32 slot, u32 val)
178{
179 u32 ret = padData[port][slot].stat70bit;
180
181 padData[port][slot].stat70bit = val;
182
183 return ret;
184}
185
186static u32 setupTransferData(u32 index, u32 port, u32 slot)
187{
188
189 if(padData[port][slot].in_size > 0)
190 {
191 int i;
192
193 for(i=0; (u32)i < padData[port][slot].in_size; i++)
194 {
195 sio2_td.in[sio2_td.in_size] = padData[port][slot].in_buffer[i];
196 sio2_td.in_size++;
197 }
198 }
199
200 sio2_td.out_size += padData[port][slot].out_size;
201
202 sio2_td.port_ctrl1[port] = padData[port][slot].port_ctrl1;
203 sio2_td.port_ctrl2[port] = padData[port][slot].port_ctrl2;
204 sio2_td.regdata[index] = (padData[port][slot].reg_data & 0xFFFFFFFC) | (port & 0x3);
205
206 sio2_td.regdata[index+1] = 0;
207
208 return (index+1);
209}
210
211u32 readStat6cBit(u32 bit, sio2_transfer_data_t *td)
212{
213 return( (td->stat6c & (0x00010000 << bit)) != 0);
214}
215
216u32 readSio2OutBuffer(u32 bit, u32 port, u32 slot)
217{
218 if(((sio2_td.stat6c >> 13) & 0x1) == 1)
219 {
220 padData[port][slot].error = 1;
221 return 0;
222 }
223 else
224 {
225 if(readStat6cBit(bit, &sio2_td) == 1)
226 {
227 padData[port][slot].error = 1;
228 return 0;
229 }
230 else
231 {
232 padData[port][slot].error = 0;
233
234 if( padData[port][slot].out_size > 0)
235 {
236 int i;
237
238 for(i=0; (u32)i < padData[port][slot].out_size; i++)
239 {
240 padData[port][slot].out_buffer[i] = sio2_td.out[sio2_td.out_size];
241 sio2_td.out_size++;
242 }
243 }
244
245 return 1;
246 }
247 }
248}
249
250u32 padTransfer(u32 slot)
251{
252 u32 stat70;
253 u32 trans_count = 0, port0_start = 0, port1_start = 0;
254 u32 val_port0 = 0;
255 u32 val_port1 = 0;
256
257 sio2_td.in_size = 0;
258 sio2_td.out_size = 0;
259 sio2_td.in_dma.addr = 0;
260 sio2_td.out_dma.addr = 0;
261
262 stat70 = sio2_stat70_get();
263
264 pdSetStat70bit(0, slot, (stat70 >> 4) & 1);
265 pdSetStat70bit(1, slot, (stat70 >> 5) & 1);
266
267 if( padData[0][slot].active == 1 )
268 {
269 if(change_slot_buffer[4] == 1)
270 {
271 val_port0 = 1;
272 port0_start = 0;
273 trans_count = setupTransferData(0, 0, slot);
274 }
275 }
276
277 if( padData[1][slot].active == 1 )
278 {
279 if(change_slot_buffer[5] == 1)
280 {
281 val_port1 = 1;
282 port1_start = trans_count;
283 trans_count = setupTransferData(trans_count, 1, slot);
284 }
285 }
286
287 /* These two blocks of code change position before v3.6.
288 At v3.3 and earlier, they were within the transfer block below. At v3.0, there were no checks on change_slot_buffer. */
289 if(padData[0][slot].active == 1)
290 {
291 if(change_slot_buffer[4] != 1)
292 padData[0][slot].error = 0xA;
293 }
294
295 if(padData[1][slot].active == 1)
296 {
297 if(change_slot_buffer[5] != 1)
298 padData[1][slot].error = 0xA;
299 }
300
301 if(trans_count != 0)
302 {
303#ifndef BUILDING_XPADMAN
304 sio2_pad_transfer_init();
305#endif
306
307#ifdef BUILDING_XPADMAN
308 sio2_transfer2( &sio2_td );
309#else
310 sio2_transfer( &sio2_td );
311#endif
312
313 sio2_td.out_size = 0;
314
315 if(val_port0 == 1)
316 {
317 readSio2OutBuffer(port0_start, 0, slot);
318 sio2_td.out_size = padData[0][slot].out_size;
319 }
320
321 if(val_port1 == 1)
322 {
323 readSio2OutBuffer(port1_start, 1, slot);
324 sio2_td.out_size = padData[1][slot].out_size;
325 }
326
327 return 1;
328 }
329
330 return 0;
331}
332
333void pdTransfer(void)
334{
335 u32 slot;
336
337#ifdef BUILDING_XPADMAN
338 sio2_pad_transfer_init();
339#endif
340
341 transferCount++;
342
343 for(slot=0; slot < 4; slot++)
344 {
345 if( (padData[0][slot].active == 1) || (padData[1][slot].active == 1) )
346 {
347 if(slot > 0) mtapChangeSlot(slot);
348
349 padTransfer(slot);
350 }
351 }
352
353 mtapChangeSlot(0);
354
355#ifdef BUILDING_XPADMAN
356 sio2_transfer_reset2();
357#endif
358}
359
360u32 pdGetStat70bit(u32 port, u32 slot)
361{
362 return padData[port][slot].stat70bit;
363}
364
365void pdReset(void)
366{
367 int i,j;
368
369 for(i=0; i < 2; i++)
370 {
371 for(j=0; j < 4; j++)
372 {
373 padData[i][j].active = 0;
374 padData[i][j].stat70bit = 0; //This is probably more correct, compared to the original line (below)
375 }
376
377 //padData[i+1][0].stat70bit = 0; //BUG: can cause buffer overrun.
378 }
379
380 sio2_td.in = sio2_in_buffer;
381 sio2_td.out = sio2_out_buffer;
382}
383
384//In versions before v3.6, only the slot argument was present.
385static u32 SlotCheckConnection(u32 port, u32 slot)
386{
387 u32 stat70;
388
389 sio2_td.in_size = 0;
390 sio2_td.out_size = 0;
391 sio2_td.out_dma.addr = 0;
392 sio2_td.in_dma.addr = 0;
393
394 if(change_slot_buffer[4+port] == 1)
395 {
396#ifndef BUILDING_XPADMAN
397 sio2_pad_transfer_init();
398#endif
399
400 //In versions before v3.6, this outer check did not exist.
401 stat70 = sio2_stat70_get();
402
403 //In versions before v3.6, stat70 is always set regardless of the slot selected.
404 switch(port)
405 {
406 case 0:
407 pdSetStat70bit(0, slot, (stat70 >> 4) & 0x1);
408 break;
409 case 1:
410 pdSetStat70bit(1, slot, (stat70 >> 5) & 0x1);
411 break;
412 }
413
414 //In versions before v3.6, there used to be checks on change_slot_buffer[] and independent calls to setupTransferData, for each port (very much like padTransfer).
415 setupTransferData(0, port, slot);
416
417 //As a result, there is neither a check on whether there is data to send.
418#ifdef BUILDING_XPADMAN
419 sio2_transfer2( &sio2_td );
420#else
421 sio2_transfer( &sio2_td );
422#endif
423
424 sio2_td.out_size = 0;
425
426 //There used to be independent calls to readSio2OutBuffer for each port too.
427 readSio2OutBuffer(0, port, slot);
428 sio2_td.out_size = padData[port][slot].out_size;
429
430 //This used to be per port too.
431 if(change_slot_buffer[4+port] != 1)
432 padData[port][slot].error = 0xA;
433
434 return 1;
435 }
436
437 return 0;
438}
439
440u32 pdCheckConnection(u32 port, u32 slot)
441{
442 u32 res;
443 u32 ret = 0;
444
445#ifndef BUILDING_XPADMAN
446 if (slot > 0)
447 {
448 return 0;
449 }
450#endif
451
452#ifdef BUILDING_XPADMAN
453 sio2_pad_transfer_init();
454#endif
455
456 change_slot_buffer[0] = slot;
457 change_slot_buffer[1] = slot;
458 change_slot_buffer[2] = -1;
459 change_slot_buffer[3] = -1;
460
461#ifdef BUILDING_XPADMAN
462 sio2_mtap_change_slot(change_slot_buffer);
463#else
464 pd_set_change_slot_buffer(change_slot_buffer);
465#endif
466
467 res = pdGetStat70bit(0, slot);
468 setupReadData(0, slot, res);
469
470 res = pdGetStat70bit(1, slot);
471 setupReadData(1, slot, res);
472
473
474 if(SlotCheckConnection(port, slot) == 1)
475 {
476 if( padData[port][slot].error == 0 )
477 ret = 1;
478 }
479
480 change_slot_buffer[0] = 0;
481 change_slot_buffer[1] = 0;
482 change_slot_buffer[2] = -1;
483 change_slot_buffer[3] = -1;
484
485#ifdef BUILDING_XPADMAN
486 sio2_mtap_change_slot(change_slot_buffer);
487#else
488 pd_set_change_slot_buffer(change_slot_buffer);
489#endif
490
491#ifdef BUILDING_XPADMAN
492 sio2_transfer_reset2();
493#endif
494
495 return ret;
496}
497
498s32 pdGetError(u32 port, u32 slot)
499{
500 if(port < 2)
501 return padData[port][slot].error;
502 else
503 return -1;
504}
505
506u32 pdSetCtrl1(u32 port, u32 slot, u32 ctrl)
507{
508 if(port < 2)
509 {
510 padData[port][slot].port_ctrl1 = ctrl;
511 return 1;
512 }
513
514 return 0;
515}
516
517u32 pdSetCtrl2(u32 port, u32 slot, u32 ctrl)
518{
519 if(port < 2)
520 {
521 padData[port][slot].port_ctrl2 = ctrl;
522 return 1;
523 }
524
525 return 0;
526
527}
528
529u32 pdSetInSize(u32 port, u32 slot, u32 size)
530{
531 if(port < 2)
532 {
533 padData[port][slot].in_size = size;
534 return size;
535 }
536
537 return 0;
538}
539
540u32 pdSetOutSize(u32 port, u32 slot, u32 size)
541{
542 if(port < 2)
543 {
544 padData[port][slot].out_size = size;
545 return size;
546 }
547
548 return 0;
549
550}
551
552u32 pdSetInBuffer(u32 port, u32 slot, u32 size, const u8 *buf)
553{
554 if(port < 2)
555 {
556 if(size == 0) size = padData[port][slot].in_size;
557
558 if(size > 0)
559 {
560 int i;
561
562 for(i=0; (u32)i < size; i++)
563 padData[port][slot].in_buffer[i] = buf[i];
564 }
565
566 return size;
567 }
568
569 return 0;
570}
571
572u32 pdGetOutBuffer(u32 port, u32 slot, u32 size, u8 *buf)
573{
574 if(port < 2)
575 {
576 if(size == 0) size = padData[port][slot].out_size;
577
578 if(size > 0)
579 {
580 int i;
581
582 for(i=0; (u32)i < size; i++)
583 buf[i] = padData[port][slot].out_buffer[i];
584 }
585
586 return size;
587 }
588
589 return 0;
590}