PS2SDK
PS2 Homebrew Libraries
padInit.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 "freepad.h"
14 #include "stdio.h"
15 #include "thevent.h"
16 #include "thbase.h"
17 #include "intrman.h"
18 #include "vblank.h"
19 #ifdef BUILDING_XPADMAN
20 #include "xsio2man.h"
21 #endif
22 #include "sifman.h"
23 #include "sio2Cmds.h"
24 #include "sysmem.h"
25 #include "padData.h"
26 
27 int pad_port;
28 int pad_slot;
29 u32 mainThreadCount2;
30 u32 pad_portdata[2];
31 /* It is very important that sif_buffer and padState are right after each other. */
32 u32 sif_buffer[4] __attribute__((aligned(4)));
33 padState_t padState[2][4];
34 u32 openSlots[2];
35 vblankData_t vblankData;
36 int padman_init;
37 void *pad_ee_addr;
38 int thpri_hi;
39 int thpri_lo;
40 SifDmaTransfer_t sifdma_td[9]; //Original was likely 16 descriptors.
41 
42 int vblank_end = 0;
43 u32 frame_count = 0;
44 int sifdma_id = 0;
45 u32 vblankStartCount = 0;
46 s32 mainThreadCount = 0;
47 
48 static void TransferThread(void *arg)
49 {
50  (void)arg;
51 
52  while(1)
53  {
54  WaitClearEvent(vblankData.eventflag, EF_VB_TRANSFER, WEF_AND|WEF_CLEAR, NULL);
55  pdTransfer();
56  SetEventFlag(vblankData.eventflag, EF_VB_TRANSFER_DONE);
57  }
58 }
59 
60 u32 padSetupEEButtonData(u32 port, u32 slot, padState_t *pstate)
61 {
62  u8 *data = pad_ee_addr ? pstate->ee_pdata.data : pstate->ee_old_pdata.data;
63  if(padState[port][slot].buttonDataReady == 1)
64  {
65  int i;
66 
67  data[0] = 0;
68  data[1] = padState[port][slot].modeCurId;
69  data[31] = padState[port][slot].buttonStatus[2];
70 
71  for(i=2; i < 31; i++)
72  data[i] = padState[port][slot].buttonStatus[i+1];
73 
74  if(padState[port][slot].modeCurId == 0x12)
75  {
76  data[2] = 0xFF,
77  data[3] = 0xFF;
78  data[4] = 0;
79  data[5] = 0;
80  }
81 
82  //New in v3.6
83  if(padState[port][slot].modeCurId == 0x79)
84  {
85  int value;
86 
87  //Check button status & update pressure data
88  value = ~((data[2] << 8) | data[3]);
89  if(value & 0x2000)
90  {
91  if(data[8] == 0)
92  data[8] = 1;
93  }
94  else
95  {
96  {
97  data[8] = 0;
98  }
99  }
100 
101  if(value & 0x8000)
102  {
103  if(data[9] == 0)
104  data[9] = 1;
105  }
106  else
107  {
108  {
109  data[9] = 0;
110  }
111  }
112 
113  if(value & 0x1000)
114  {
115  if(data[10] == 0)
116  data[10] = 1;
117  }
118  else
119  {
120  {
121  data[10] = 0;
122  }
123  }
124 
125  if(value & 0x4000)
126  {
127  if(data[11] == 0)
128  data[11] = 1;
129  }
130  else
131  {
132  {
133  data[11] = 0;
134  }
135  }
136 
137  if(value & 0x0010)
138  {
139  if(data[12] == 0)
140  data[12] = 1;
141  }
142  else
143  {
144  {
145  data[12] = 0;
146  }
147  }
148 
149  if(value & 0x0020)
150  {
151  if(data[13] == 0)
152  data[13] = 1;
153  }
154  else
155  {
156  {
157  data[13] = 0;
158  }
159  }
160 
161  if(value & 0x0040)
162  {
163  if(data[14] == 0)
164  data[14] = 1;
165  }
166  else
167  {
168  {
169  data[14] = 0;
170  }
171  }
172 
173  if(value & 0x0080)
174  {
175  if(data[15] == 0)
176  data[15] = 1;
177  }
178  else
179  {
180  {
181  data[15] = 0;
182  }
183  }
184 
185  if(value & 0x0004)
186  {
187  if(data[16] == 0)
188  data[16] = 1;
189  }
190  else
191  {
192  {
193  data[16] = 0;
194  }
195  }
196 
197  if(value & 0x0008)
198  {
199  if(data[17] == 0)
200  data[17] = 1;
201  }
202  else
203  {
204  {
205  data[17] = 0;
206  }
207  }
208 
209  if(value & 0x0001)
210  {
211  if(data[18] == 0)
212  data[18] = 1;
213  }
214  else
215  {
216  {
217  data[18] = 0;
218  }
219  }
220 
221  if(value & 0x0002)
222  {
223  if(data[19] == 0)
224  data[19] = 1;
225  }
226  else
227  {
228  {
229  data[19] = 0;
230  }
231  }
232  }
233 
234  return 32;
235  }
236  else
237  {
238  int i;
239 
240  data[0] = 0xFF;
241 
242  for(i=1; i < 32; i++)
243  data[i] = 0;
244 
245  return 0;
246  }
247 }
248 
249 
250 static void DmaSendEE(void)
251 {
252  int dma_stat;
253 
254  dma_stat = sceSifDmaStat(sifdma_id);
255 
256  if(dma_stat >= 0)
257  {
258  if( (frame_count % 240) == 0)
259  {
260  M_KPRINTF("DMA Busy ID = %08x ret = %d\n", sifdma_id, dma_stat);
261  M_KPRINTF(" SB_STAT = %08x\n", SB_STAT);
262  }
263  }
264  else
265  {
266  u32 port, slot;
267  u32 sifdma_count = 0;
268 
269  /* This is where the 128*2 bytes of 'garbage' gets sent to EE.
270  I believe that only 16 bytes should have been sent, used for checking
271  which ports/slots are open on the EE (padGetConnection). However
272  someone made a mistake and sent 128 bytes instead :-) Its the first
273  112 (128-16) bytes of padState[0][0] which gets sent along with the
274  sif_buffer, which I think clearly indicates that sending 128 bytes
275  is an error. - Lukasz
276  */
277 
278  sif_buffer[0]++;
279  sif_buffer[1] = pad_portdata[0];
280  sif_buffer[2] = pad_portdata[1];
281 
282  if (pad_ee_addr)
283  {
284  if( (sif_buffer[0] % 2) == 0)
285  sifdma_td[sifdma_count].dest = (void *)(((u8 *)pad_ee_addr) + 128);
286  else
287  sifdma_td[sifdma_count].dest = pad_ee_addr;
288 
289  sifdma_td[sifdma_count].src = sif_buffer;
290  sifdma_td[sifdma_count].size = 128;
291  sifdma_td[sifdma_count].attr = 0;
292  sifdma_count += 1;
293  }
294 
295  for(port=0; port < 2; port++)
296  {
297  for(slot=0; slot < 4; slot++)
298  {
299  if( (openSlots[port] >> slot) & 1 )
300  {
301  padState_t *p = &padState[port][slot];
302 
303  // Setup EE pad data
304  p->ee_pdata.frame = p->frame;
305  p->ee_pdata.findPadRetries = p->findPadRetries;
306  p->ee_pdata.modeConfig = p->modeConfig;
307  p->ee_pdata.modeCurId = p->modeCurId;
308  p->ee_pdata.model = p->model;
309  p->ee_pdata.buttonDataReady = p->buttonDataReady;
310  p->ee_pdata.nrOfModes = p->numModes;
311  p->ee_pdata.modeCurOffs = p->modeCurOffs;
312  p->ee_pdata.nrOfActuators = p->numActuators;
313  p->ee_pdata.numActComb = p->numActComb;
314  p->ee_pdata.val_c6 = p->val_c6;
315  p->ee_pdata.mode = p->mode;
316  p->ee_pdata.lock = p->lock;
317  p->ee_pdata.actDirSize = p->ee_actDirectSize;
318  p->ee_pdata.state = p->state;
319  p->ee_pdata.reqState = p->reqState;
320  p->ee_pdata.currentTask = p->currentTask;
321  p->ee_old_pdata.frame = p->frame;
322  p->ee_old_pdata.model = p->model;
323  p->ee_old_pdata.state = p->state;
324  if (p->state == PAD_STATE_ERROR && p->findPadRetries != 0)
325  {
326  p->ee_old_pdata.state = PAD_STATE_FINDPAD;
327  }
328  p->ee_old_pdata.reqState = p->reqState;
329 
330  p->frame++;
331 
332  p->ee_pdata.runTask = p->runTask;
333 
334  p->ee_pdata.actDirData[0] = p->ee_actDirectData.data32[0];
335  p->ee_pdata.actDirData[1] = p->ee_actDirectData.data32[1];
336  p->ee_pdata.actAlignData[0] = p->ee_actAlignData.data32[0];
337  p->ee_pdata.actAlignData[1] = p->ee_actAlignData.data32[1];
338 
339  p->ee_pdata.actData[0] = p->actData.data32[0];
340  p->ee_pdata.actData[1] = p->actData.data32[1];
341  p->ee_pdata.actData[2] = p->actData.data32[2];
342  p->ee_pdata.actData[3] = p->actData.data32[3];
343  p->ee_pdata.combData[0] = p->combData.data32[0];
344  p->ee_pdata.combData[1] = p->combData.data32[1];
345  p->ee_pdata.combData[2] = p->combData.data32[2];
346  p->ee_pdata.combData[3] = p->combData.data32[3];
347 
348  p->ee_pdata.modeTable[0] = p->modeTable.data32[0];
349  p->ee_pdata.modeTable[1] = p->modeTable.data32[1];
350 
351  p->ee_pdata.stat70bit = p->stat70bit;
352 
353  *((pad_ee_addr) ? &(p->ee_pdata.length) : &(p->ee_old_pdata.length)) = (p->buttonDataReady == 1) ? padSetupEEButtonData(port, slot, p) : 0;
354 
355  if( (p->frame & 1) == 0)
356  sifdma_td[sifdma_count].dest = (void*)p->padarea_ee_addr;
357  else
358  sifdma_td[sifdma_count].dest = (void*)(p->padarea_ee_addr + (pad_ee_addr ? 128 : 64));
359 
360  sifdma_td[sifdma_count].src = pad_ee_addr ? (void *)&p->ee_pdata : (void *)&p->ee_old_pdata;
361  sifdma_td[sifdma_count].size = pad_ee_addr ? 128 : 64;
362  sifdma_td[sifdma_count].attr = 0;
363 
364  sifdma_count++;
365  }
366  }
367  }
368 
369  if(sifdma_count != 0)
370  {
371  int intr_state;
372 
373  CpuSuspendIntr(&intr_state);
374 
375  sifdma_id = sceSifSetDma( sifdma_td, sifdma_count);
376 
377  CpuResumeIntr(intr_state);
378 
379  if(sifdma_id == 0)
380  M_KPRINTF("sceSifSetDma failed\n");
381  }
382  }
383 }
384 
385 static u32 GetThreadsStatus(padState_t *state)
386 {
387  u32 count = 0;
389 
390  if( ReferThreadStatus(state->updatepadTid, &tinfo) == 0)
391  {
392  if( (tinfo.status & THS_DORMANT) == 0) count++;
393  }
394 
395  if( ReferThreadStatus(state->querypadTid, &tinfo) == 0)
396  {
397  if( (tinfo.status & THS_DORMANT) == 0) count++;
398  }
399 
400  if( ReferThreadStatus(state->setmainmodeTid, &tinfo) == 0)
401  {
402  if( (tinfo.status & THS_DORMANT) == 0) count++;
403  }
404 
405  if( ReferThreadStatus(state->setactalignTid, &tinfo) == 0)
406  {
407  if( (tinfo.status & THS_DORMANT) == 0) count++;
408  }
409 
410  if( ReferThreadStatus(state->setbuttoninfoTid, &tinfo) == 0)
411  {
412  if( (tinfo.status & THS_DORMANT) == 0) count++;
413  }
414 
415  if( ReferThreadStatus(state->setvrefparamTid, &tinfo) == 0)
416  {
417  if( (tinfo.status & THS_DORMANT) == 0) count++;
418  }
419 
420  if(count == 0)
421  return 1;
422  else
423  return 0;
424 }
425 
426 static void DeleteThreads(padState_t *state)
427 {
428  DeleteThread(state->updatepadTid);
429  DeleteThread(state->querypadTid);
430  DeleteThread(state->setmainmodeTid);
431  DeleteThread(state->setactalignTid);
432  DeleteThread(state->setbuttoninfoTid);
433  DeleteThread(state->setvrefparamTid);
434 }
435 
436 static void MainThread(void *arg)
437 {
438  (void)arg;
439 
440  while(1)
441  {
442  u32 port, slot;
443 
444  mainThreadCount++;
445 
446 #ifdef BUILDING_XPADMAN
447  if( mainThreadCount % 30 == 0 ) sio2_mtap_update_slots();
448 #endif
449 
450  for(port=0; port < 2; port++)
451  {
452  for(slot=0; slot < 4; slot++)
453  {
454  if( ((openSlots[port] >> slot) & 0x1) == 1)
455  {
456  pdSetActive(port, slot, 0);
457 
458  padState[port][slot].stat70bit = pdGetStat70bit(port, slot);
459 
460  if(padState[port][slot].runTask != TASK_NONE)
461  {
462  if(padState[port][slot].runTask == TASK_PORT_CLOSE)
463  {
464  padState[port][slot].currentTask = padState[port][slot].runTask;
465  padState[port][slot].runTask = TASK_NONE;
466  padState[port][slot].reqState = PAD_RSTAT_BUSY;
467 
468  SetEventFlag(padState[port][slot].eventflag, EF_EXIT_THREAD);
469  }
470  else
471  {
472  if(padState[port][slot].currentTask == TASK_UPDATE_PAD)
473  {
474  // Start Task
475  StartThread(padState[port][slot].taskTid, NULL);
476  padState[port][slot].currentTask = padState[port][slot].runTask;
477  padState[port][slot].runTask = TASK_NONE;
478  padState[port][slot].reqState = PAD_RSTAT_BUSY;
479  }
480  else
481  {
482  padState[port][slot].runTask = TASK_NONE;
483  padState[port][slot].reqState = PAD_RSTAT_FAILED;
484  }
485  }
486  }
487  }
488 
489  switch(padState[port][slot].currentTask)
490  {
491  case TASK_UPDATE_PAD:
492  {
493  SetEventFlag(padState[port][slot].eventflag, EF_UPDATE_PAD);
494  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
495  pdSetActive(port, slot, 1);
496  } break;
497 
498  case TASK_QUERY_PAD:
499  {
500  padState[port][slot].buttonDataReady = 0;
501 
502  SetEventFlag(padState[port][slot].eventflag, EF_QUERY_PAD);
503  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
504  pdSetActive(port, slot, 1);
505  } break;
506 
507  case TASK_PORT_CLOSE:
508  {
509  if(GetThreadsStatus( &padState[port][slot] ) == 1)
510  {
511  padState[port][slot].currentTask = TASK_NONE;
512  padState[port][slot].reqState = PAD_RSTAT_COMPLETE;
513  openSlots[port] ^= (1 << slot);
514 
515  DeleteThreads( &padState[port][slot] );
516  SetEventFlag(padState[port][slot].eventflag, EF_PORT_CLOSE);
517  }
518 
519  } break;
520 
521  case TASK_SET_MAIN_MODE:
522  {
523  padState[port][slot].buttonDataReady = 0;
524 
525  SetEventFlag(padState[port][slot].eventflag, EF_SET_MAIN_MODE);
526  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
527  pdSetActive(port, slot, 1);
528  } break;
529 
530  case TASK_SET_ACT_ALIGN:
531  {
532  padState[port][slot].buttonDataReady = 0;
533 
534  SetEventFlag(padState[port][slot].eventflag, EF_SET_ACT_ALIGN);
535  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
536  pdSetActive(port, slot, 1);
537  } break;
538 
539  case TASK_SET_BUTTON_INFO:
540  {
541  padState[port][slot].buttonDataReady = 0;
542 
543  SetEventFlag(padState[port][slot].eventflag, EF_SET_SET_BUTTON_INFO);
544  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
545  pdSetActive(port, slot, 1);
546  } break;
547 
548  case TASK_SET_VREF_PARAM:
549  {
550  padState[port][slot].buttonDataReady = 0;
551 
552  SetEventFlag(padState[port][slot].eventflag, EF_SET_VREF_PARAM);
553  WaitEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_START, 0x10, 0);
554  pdSetActive(port, slot, 1);
555  } break;
556 
557  }
558  }
559  }
560 
561  // Transfer is started in VblankStart
562  vblankData.stopTransfer = 0;
563  WaitClearEvent(vblankData.eventflag, EF_VB_TRANSFER_DONE, WEF_AND|WEF_CLEAR, NULL);
564 
565  if( (openSlots[0] != 0) || (openSlots[1] != 0))
566  {
567  for(port=0; port < 2; port++)
568  {
569  for(slot=0; slot < 4; slot++)
570  {
571  if(pdIsActive(port, slot) == 1)
572  {
573  /* Signal transfer done and wait to task (reading
574  sio2 data) to be done. */
575  SetEventFlag(padState[port][slot].eventflag, EF_PAD_TRANSFER_DONE);
576  WaitEventFlag(padState[port][slot].eventflag, EF_TASK_DONE, 0x10, 0);
577  }
578  }
579  }
580  }
581 
582  // Send pad data to EE
583  DmaSendEE();
584 
585  mainThreadCount2++; // s7
586 
587  // Check for disconnected controllers
588  if(mainThreadCount2 >= 8)
589  {
590  if(mainThreadCount % 30 != 0)
591  {
592  if( pdIsActive(pad_port, pad_slot) == 1)
593  {
594  if( padState[pad_port][pad_slot].state == PAD_STATE_DISCONN)
595  pad_portdata[pad_port] &= ~(1 << pad_slot); // clear slot
596  else
597  pad_portdata[pad_port] |= (1 << pad_slot); // set slot
598  }
599  else
600  {
601  if( pdCheckConnection(pad_port, pad_slot) == 1)
602  pad_portdata[pad_port] |= (1 << pad_slot); // set slot
603  else
604  pad_portdata[pad_port] &= ~(1 << pad_slot); // clear slot
605  }
606 
607  //Move onto the next slot
608  pad_slot++;
609  if(pad_slot >= 4)
610  {
611  //Move onto the next port
612  pad_slot = 0;
613  pad_port++;
614 
615  if(pad_port >= 2) pad_port = 0;
616  }
617 
618  mainThreadCount2 = 0;
619  }
620  }
621  }
622 }
623 
624 s32 VbReferThreadStatus(vblankData_t *vData)
625 {
627  s32 ret = 0;
628 
629  if( iReferThreadStatus(vData->tid_1, &tinfo) == 0)
630  {
631  if( (tinfo.status & THS_DORMANT) == 0 )
632  ret++;
633  }
634 
635  if( iReferThreadStatus(vData->tid_2, &tinfo) == 0)
636  {
637  if( (tinfo.status & THS_DORMANT) == 0 )
638  ret++;
639  }
640 
641  return ret;
642 }
643 
644 int VblankStart(void *arg)
645 {
646  vblankData_t *vData = arg;
647 
648  vblank_end = 0;
649  vblankStartCount++;
650  frame_count++;
651 
652  if((vData->init == 1) && (vData->stopTransfer == 0))
653  {
654  vData->stopTransfer = 1;
655  iSetEventFlag(vData->eventflag, EF_VB_TRANSFER);
656  }
657 
658  /* Wait for threads to exit and signal event to padEnd */
659  if(vData->padEnd == 1)
660  {
661  if( VbReferThreadStatus(vData) == 0 )
662  iSetEventFlag(vData->eventflag, EF_VB_WAIT_THREAD_EXIT);
663  }
664 
665  return 1;
666 }
667 
668 
669 int VblankEnd(void *arg)
670 {
671  (void)arg;
672 
673  vblank_end = 1;
674  return 1;
675 }
676 
677 s32 padInit(void * ee_addr)
678 {
680  int intr_state;
682 
683  if(padman_init == 1)
684  {
685  M_PRINTF("Refresh request from EE\n.");
686  padEnd();
687  }
688 
689  vblankData.padEnd = 0;
690  vblankData.init = 0;
691  vblankData.stopTransfer = 1;
692 
693  pad_ee_addr = ee_addr;
694  pad_port = 0;
695  pad_slot = 0;
696  mainThreadCount2 = 0;
697  pad_portdata[0] = 0;
698  pad_portdata[1] = 0;
699  sif_buffer[0] = 0;
700 
701  sio2cmdReset();
702  sio2cmdInitFindPads();
703  sio2cmdInitMouse();
704  sio2cmdInitNegicon();
705  sio2cmdInitKonamiGun();
706  sio2cmdInitDigital();
707  sio2cmdInitJoystick();
708  sio2cmdInitNamcoGun();
709  sio2cmdInitAnalog();
710  sio2cmdInitJogcon();
711  sio2cmdInitConfig();
712 
713  pdReset();
714 
715  openSlots[0] = 0;
716  openSlots[1] = 0;
717 
718  event.attr = EA_MULTI;
719  event.bits = 0;
720 
721  vblankData.eventflag = CreateEventFlag(&event);
722 
723  if( vblankData.eventflag == 0)
724  {
725  M_PRINTF("padInit: CreateEventFlag failed (%d).\n", vblankData.eventflag);
726  return 0;
727  }
728 
729  thread.attr = TH_C;
730  thread.thread = &TransferThread;
731  thread.stacksize = 0x800;
732  thread.priority = thpri_hi;
733 
734  vblankData.tid_2 = CreateThread(&thread);
735 
736  if(vblankData.tid_2 == 0)
737  {
738  M_PRINTF("padInit: CreateThread TransferThread failed (%d)\n.", vblankData.tid_2);
739  return 0;
740  }
741 
742  StartThread(vblankData.tid_2, NULL);
743 
744  thread.attr = TH_C;
745  thread.thread = MainThread;
746  thread.stacksize = 0x1000;
747  thread.priority = thpri_lo;
748 
749  vblankData.tid_1 = CreateThread(&thread);
750 
751  if(vblankData.tid_1 == 0)
752  {
753  M_PRINTF("padInit: CreateThread MainThread failed (%d)\n.", vblankData.tid_1);
754  return 0;
755  }
756 
757  StartThread(vblankData.tid_1, NULL);
758 
759  CpuSuspendIntr(&intr_state);
760 
761  RegisterVblankHandler(0, 16, &VblankStart, (void*)&vblankData);
762  RegisterVblankHandler(1, 16, &VblankEnd, (void*)&vblankData);
763 
764  CpuResumeIntr(intr_state); //Original BUG: was originally a call to CpuEnableIntr with intr_state as an argument
765 
766  vblankData.init = 1;
767  padman_init = 1;
768 
769  return 1;
770 }
xsio2man.h
thbase.h
sifman.h
EA_MULTI
#define EA_MULTI
Definition: thevent.h:35
vblankData_t
Definition: freepad.h:97
padState_t
Definition: freepad.h:158
thread
Definition: thcommon.h:143
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
event
Definition: thcommon.h:71
padInit
int padInit(int mode)
Definition: libpad.c:300
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
tinfo
Definition: tty.c:47
vblank.h
stdio.h
_iop_thread
Definition: thbase.h:39
freepad.h
t_SifDmaTransfer
Definition: sifdma.h:52
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
padEnd
int padEnd(void)
Definition: libpad.c:431
sysmem.h
__attribute__
Definition: gif_registers.h:38
padData.h
intrman.h
iop_event_t
Definition: thevent.h:37
thevent.h
sio2Cmds.h
_iop_thread_status
Definition: thbase.h:68