Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / src / pad.c
blobe8024a73422f2aec7bee7b2f558111287590efa1
1 /*
2 Copyright 2009, Ifcaro, Volca
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/pad.h"
9 #include "include/ioman.h"
10 #include <libpad.h>
11 #include <timer.h>
12 #include <time.h>
14 #define MAX_PADS 4
16 // Cpu ticks per one milisecond
17 #define CLOCKS_PER_MILISEC 147456
19 // 200 ms per repeat
20 #define DEFAULT_PAD_DELAY 200
22 struct pad_data_t {
23 int port, slot;
24 u32 paddata;
25 u32 oldpaddata;
26 struct padButtonStatus buttons;
28 // pad_dma_buf is provided by the user, one buf for each pad
29 // contains the pad's current state
30 char padBuf[256] __attribute__((aligned(64)));
32 char actAlign[6];
33 int actuators;
36 /// current time in miliseconds (last update time)
37 static u32 curtime = 0;
38 static u32 time_since_last = 0;
40 static unsigned short pad_count;
41 static struct pad_data_t pad_data[MAX_PADS];
43 // gathered pad data
44 static u32 paddata;
45 static u32 oldpaddata;
47 static int delaycnt[16];
48 static int paddelay[16];
50 // KEY_ to PAD_ conversion table
51 static const int keyToPad[17] = {
52 -1,
53 PAD_LEFT,
54 PAD_DOWN,
55 PAD_RIGHT,
56 PAD_UP,
57 PAD_START,
58 PAD_R3,
59 PAD_L3,
60 PAD_SELECT,
61 PAD_SQUARE,
62 PAD_CROSS,
63 PAD_CIRCLE,
64 PAD_TRIANGLE,
65 PAD_R1,
66 PAD_L1,
67 PAD_R2,
68 PAD_L2
72 * waitPadReady()
74 static int waitPadReady(struct pad_data_t* pad) {
75 int state;
77 // busy wait for the pad to get ready
78 do {
79 state = padGetState(pad->port, pad->slot);
80 } while((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1) && (state != PAD_STATE_DISCONN));
82 return state;
85 static int initializePad(struct pad_data_t* pad) {
86 int tmp;
87 int modes;
88 int i;
90 // is there any device connected to that port?
91 if (waitPadReady(pad) == PAD_STATE_DISCONN) {
92 return 1; // nope, don't waste your time here!
95 // How many different modes can this device operate in?
96 // i.e. get # entrys in the modetable
97 modes = padInfoMode(pad->port, pad->slot, PAD_MODETABLE, -1);
98 LOG("PAD The device has %d modes: ", modes);
100 if (modes > 0) {
101 LOG("( ");
103 for (i = 0; i < modes; i++) {
104 tmp = padInfoMode(pad->port, pad->slot, PAD_MODETABLE, i);
105 LOG("%d ", tmp);
108 LOG(")\n");
111 tmp = padInfoMode(pad->port, pad->slot, PAD_MODECURID, 0);
112 LOG("PAD It is currently using mode %d\n", tmp);
114 // If modes == 0, this is not a Dual shock controller
115 // (it has no actuator engines)
116 if (modes == 0) {
117 LOG("PAD This is a digital controller?\n");
118 return 1;
121 // Verify that the controller has a DUAL SHOCK mode
122 i = 0;
123 do {
124 if (padInfoMode(pad->port, pad->slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK)
125 break;
126 i++;
127 } while (i < modes);
129 if (i >= modes) {
130 LOG("PAD This is no Dual Shock controller\n");
131 return 1;
134 // If ExId != 0x0 => This controller has actuator engines
135 // This check should always pass if the Dual Shock test above passed
136 tmp = padInfoMode(pad->port, pad->slot, PAD_MODECUREXID, 0);
137 if (tmp == 0) {
138 LOG("PAD This is no Dual Shock controller??\n");
139 return 1;
142 LOG("PAD Enabling dual shock functions\n");
144 // When using MMODE_LOCK, user cant change mode with Select button
145 padSetMainMode(pad->port, pad->slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);
147 waitPadReady(pad);
148 tmp = padInfoPressMode(pad->port, pad->slot);
149 LOG("PAD infoPressMode: %d\n", tmp);
151 waitPadReady(pad);
152 tmp = padEnterPressMode(pad->port, pad->slot);
153 LOG("PAD enterPressMode: %d\n", tmp);
155 waitPadReady(pad);
156 pad->actuators = padInfoAct(pad->port, pad->slot, -1, 0);
157 LOG("PAD # of actuators: %d\n", pad->actuators);
159 if (pad->actuators != 0) {
160 pad->actAlign[0] = 0; // Enable small engine
161 pad->actAlign[1] = 1; // Enable big engine
162 pad->actAlign[2] = 0xff;
163 pad->actAlign[3] = 0xff;
164 pad->actAlign[4] = 0xff;
165 pad->actAlign[5] = 0xff;
167 waitPadReady(pad);
168 tmp = padSetActAlign(pad->port, pad->slot, pad->actAlign);
169 LOG("PAD padSetActAlign: %d\n", tmp);
170 } else {
171 LOG("PAD Did not find any actuators.\n");
174 waitPadReady(pad);
176 return 1;
179 static int readPad(struct pad_data_t* pad)
181 int rcode = 0;
183 int ret = padRead(pad->port, pad->slot, &pad->buttons); // port, slot, buttons
185 if (ret != 0)
187 u32 newpdata = 0xffff ^ pad->buttons.btns;
189 if (newpdata != 0x0) // something
190 rcode = 1;
191 else
192 rcode = 0;
194 pad->oldpaddata = pad->paddata;
195 pad->paddata = newpdata;
197 // merge into the global vars
198 paddata |= pad->paddata;
201 return rcode;
204 /** Returns delay (in miliseconds) specified for the given key.
205 * @param id The button id
206 * @param repeat Boolean value specifying if we want initial key delay (0) or the repeat key delay (1)
207 * @return the delay to the next key event
209 static int getKeyDelay(int id, int repeat) {
210 int delay = paddelay[id - 1];
212 // if not in repeat, the delay is enlarged
213 if (!repeat)
214 delay *= 3;
216 return delay;
219 /** polling method. Call every frame. */
220 int readPads() {
221 int i;
222 oldpaddata = paddata;
223 paddata = 0;
225 // in ms.
226 u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
227 time_since_last = newtime - curtime;
228 curtime = newtime;
230 int rslt = 0;
232 for (i = 0; i < pad_count; ++i) {
233 rslt |= readPad(&pad_data[i]);
236 for (i = 0; i < 16; ++i) {
237 if (getKeyPressed(i + 1))
238 delaycnt[i] -= time_since_last;
239 else
240 delaycnt[i] = getKeyDelay(i + 1, 0);
243 return rslt;
246 /** Key getter with key repeats.
247 * @param id The button ID
248 * @return nonzero if button is being pressed just now
250 int getKey(int id) {
251 if ( (id <= 0) || (id >= 17) )
252 return 0;
254 int kid = id - 1;
256 // either the button was not pressed this frame, then reset counter and return
257 // or it was, then handle the repetition
258 if (getKeyOn(id)) {
259 delaycnt[kid] = getKeyDelay(id, 0);
260 return 1;
263 if(!getKeyPressed(id))
264 return 0;
266 if(delaycnt[kid] <= 0) {
267 delaycnt[kid] = getKeyDelay(id, 1);
268 return 1;
271 return 0;
274 /** Detects key-on event. Returns true if the button was not pressed the last frame but is pressed this frame.
275 * @param id The button ID
276 * @return nonzero if button is being pressed just now
278 int getKeyOn(int id) {
279 if ( (id<=0) || (id>=17) )
280 return 0;
282 // old v.s. new pad data
283 int keyid = keyToPad[id];
285 return (paddata & keyid) && (!(oldpaddata & keyid));
288 /** Detects key-off event. Returns true if the button was pressed the last frame but is not pressed this frame.
289 * @param id The button ID
290 * @return nonzero if button is being released
292 int getKeyOff(int id) {
293 if ( (id<=0) || (id>=17) )
294 return 0;
296 // old v.s. new pad data
297 int keyid = keyToPad[id];
299 return (!(paddata & keyid)) && (oldpaddata & keyid);
302 /** Returns true (nonzero) if the button is currently pressed
303 * @param id The button ID
304 * @return nonzero if button is being held
306 int getKeyPressed(int id) {
307 // old v.s. new pad data
308 int keyid = keyToPad[id];
310 return (paddata & keyid);
313 /** Sets the delay to wait for button repetition event to occur.
314 * @param button The button ID
315 * @param btndelay The button delay (in query count)
317 void setButtonDelay(int button, int btndelay) {
318 if ( (button<=0) || (button>=17) )
319 return;
321 paddelay[button-1] = btndelay;
324 int getButtonDelay(int button) {
325 if ( (button<=0) || (button>=17) )
326 return 0;
328 return paddelay[button-1];
331 /** Unloads a single pad.
332 * @see unloadPads */
333 static void unloadPad(struct pad_data_t* pad) {
334 padPortClose(pad->port, pad->slot);
337 /** Unloads all pads. Use to terminate the usage of the pads. */
338 void unloadPads() {
339 int i;
341 for (i = 0; i < pad_count; ++i)
342 unloadPad(&pad_data[i]);
344 padReset();
347 /** Tries to start a single pad.
348 * @param pad The pad data holding structure
349 * @return 0 Error, != 0 Ok */
350 static int startPad(struct pad_data_t* pad) {
351 if(padPortOpen(pad->port, pad->slot, pad->padBuf) == 0) {
352 return 0;
355 if(!initializePad(pad)) {
356 return 0;
359 waitPadReady(pad);
360 return 1;
363 /** Starts all pads.
364 * @return Count of dual shock compatible pads. 0 if none present. */
365 int startPads() {
366 // scan for pads that exist... at least one has to be present
367 pad_count = 0;
369 int maxports = padGetPortMax();
371 int port; // 0 -> Connector 1, 1 -> Connector 2
372 int slot; // Always zero if not using multitap
374 for (port = 0; port < maxports; ++port) {
375 int maxslots = padGetSlotMax(port);
377 for (slot = 0; slot < maxslots; ++slot) {
379 struct pad_data_t* cpad = &pad_data[pad_count];
381 cpad->port = port;
382 cpad->slot = slot;
384 if (startPad(cpad))
385 ++pad_count;
388 if (pad_count >= MAX_PADS)
389 break; // enough already!
392 int n;
393 for(n=0; n<16; ++n) {
394 delaycnt[n]=DEFAULT_PAD_DELAY;
395 paddelay[n]=DEFAULT_PAD_DELAY;
398 return pad_count;
401 void padStoreSettings(int* buffer) {
402 int i;
404 for (i = 0; i < 16; i++)
405 buffer[i] = paddelay[i];
409 void padRestoreSettings(int* buffer) {
410 int i;
412 for (i = 0; i < 16; i++)
413 paddelay[i] = buffer[i];