PS2SDK
PS2 Homebrew Libraries
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 
24 typedef 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 
40 static padData_t padData[2][4];
41 
42 static sio2_transfer_data_t sio2_td;
43 static u8 sio2_in_buffer[256];
44 static u8 sio2_out_buffer[256];
45 static s32 change_slot_buffer[8];
46 
47 static int transferCount;
48 
49 #ifndef BUILDING_XPADMAN
50 static 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 
67 u32 pdGetInSize(u8 id)
68 {
69  if(id == 0) id = PAD_ID_DIGITAL;
70 
71  return (PAD_ID_LO(id)*2)+3;
72 }
73 
74 u32 pdGetOutSize(u8 id)
75 {
76  if(id == 0) id = PAD_ID_DIGITAL;
77 
78  return (PAD_ID_LO(id)*2)+3;
79 }
80 
81 u32 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 
92 u32 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 
104 u32 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 
138 u32 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 
147 u32 pdIsActive(u32 port, u32 slot)
148 {
149  return padData[port][slot].active;
150 }
151 
152 static 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 
177 u32 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 
186 static 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 
211 u32 readStat6cBit(u32 bit, sio2_transfer_data_t *td)
212 {
213  return( (td->stat6c & (0x00010000 << bit)) != 0);
214 }
215 
216 u32 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 
250 u32 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 
333 void pdTransfer(void)
334 {
335  u32 slot;
336 
337 #ifdef BUILDING_XPADMAN
338  sio2_pad_transfer_init2();
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 
360 u32 pdGetStat70bit(u32 port, u32 slot)
361 {
362  return padData[port][slot].stat70bit;
363 }
364 
365 void 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.
385 static 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 
440 u32 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_init2();
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 
498 s32 pdGetError(u32 port, u32 slot)
499 {
500  if(port < 2)
501  return padData[port][slot].error;
502  else
503  return -1;
504 }
505 
506 u32 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 
517 u32 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 
529 u32 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 
540 u32 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 
552 u32 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 
572 u32 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 }
xsio2man.h
sifman.h
padData_t
Definition: padData.c:24
sio2man.h
irx.h
stdio.h
freepad.h
sio2_transfer_data_t
Definition: sio2man.h:33
padData.h
sio2Cmds.h