1 // Copyright (c) 2012- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #include <cmath>
19 #include <mutex>
20 
21 #include "Common/Serialize/Serializer.h"
22 #include "Common/Serialize/SerializeFuncs.h"
23 #include "Core/HLE/HLE.h"
24 #include "Core/HLE/FunctionWrappers.h"
25 #include "Core/MIPS/MIPS.h"
26 #include "Core/CoreTiming.h"
27 #include "Core/MemMapHelpers.h"
28 #include "Core/Replay.h"
29 #include "Core/Util/AudioFormat.h"  // for clamp_u8
30 #include "Core/HLE/sceCtrl.h"
31 #include "Core/HLE/sceDisplay.h"
32 #include "Core/HLE/sceKernel.h"
33 #include "Core/HLE/sceKernelThread.h"
34 #include "Core/HLE/sceKernelInterrupt.h"
35 
36 /* Index for the two analog directions */
37 #define CTRL_ANALOG_X   0
38 #define CTRL_ANALOG_Y   1
39 #define CTRL_ANALOG_CENTER 128
40 
41 #define CTRL_MODE_DIGITAL   0
42 #define CTRL_MODE_ANALOG    1
43 
44 const u32 NUM_CTRL_BUFFERS = 64;
45 
46 enum {
47 	CTRL_WAIT_POSITIVE = 1,
48 	CTRL_WAIT_NEGATIVE = 2,
49 };
50 
51 struct CtrlData {
52 	u32_le frame;
53 	u32_le buttons;
54 	// The PSP has only one stick, but has space for more info.
55 	// The second stick is populated for HD remasters and possibly in the PSP emulator on PS3/Vita.
56 	u8 analog[2][2];
57 	u8 unused[4];
58 };
59 
60 struct CtrlLatch {
61 	u32_le btnMake;
62 	u32_le btnBreak;
63 	u32_le btnPress;
64 	u32_le btnRelease;
65 };
66 
67 
68 //////////////////////////////////////////////////////////////////////////
69 // STATE BEGIN
70 static bool analogEnabled = false;
71 static int ctrlLatchBufs = 0;
72 static u32 ctrlOldButtons = 0;
73 
74 static CtrlData ctrlBufs[NUM_CTRL_BUFFERS];
75 static CtrlData ctrlCurrent;
76 static u32 ctrlBuf = 0;
77 static u32 ctrlBufRead = 0;
78 static CtrlLatch latch;
79 static u32 dialogBtnMake = 0;
80 
81 static int ctrlIdleReset = -1;
82 static int ctrlIdleBack = -1;
83 
84 static int ctrlCycle = 0;
85 
86 static std::vector<SceUID> waitingThreads;
87 static std::mutex ctrlMutex;
88 
89 static int ctrlTimer = -1;
90 
91 static u16 leftVibration = 0;
92 static u16 rightVibration = 0;
93 // The higher the dropout, the longer Vibration will run
94 static u8 vibrationLeftDropout = 160;
95 static u8 vibrationRightDropout = 160;
96 
97 // STATE END
98 //////////////////////////////////////////////////////////////////////////
99 
100 // Not savestated, this is emu state.
101 // Not related to sceCtrl*RapidFire(), although it may do the same thing.
102 static bool emuRapidFire = false;
103 static u32 emuRapidFireFrames = 0;
104 
105 // These buttons are not affected by rapid fire (neither is analog.)
106 const u32 CTRL_EMU_RAPIDFIRE_MASK = CTRL_UP | CTRL_DOWN | CTRL_LEFT | CTRL_RIGHT;
107 
__CtrlUpdateLatch()108 static void __CtrlUpdateLatch()
109 {
110 	std::lock_guard<std::mutex> guard(ctrlMutex);
111 	u64 t = CoreTiming::GetGlobalTimeUs();
112 
113 	u32 buttons = ctrlCurrent.buttons;
114 	if (emuRapidFire && (emuRapidFireFrames % 10) < 5)
115 		buttons &= CTRL_EMU_RAPIDFIRE_MASK;
116 
117 	ReplayApplyCtrl(buttons, ctrlCurrent.analog, t);
118 
119 	// Copy in the current data to the current buffer.
120 	ctrlBufs[ctrlBuf] = ctrlCurrent;
121 	ctrlBufs[ctrlBuf].buttons = buttons;
122 
123 	u32 changed = buttons ^ ctrlOldButtons;
124 	latch.btnMake |= buttons & changed;
125 	latch.btnBreak |= ctrlOldButtons & changed;
126 	latch.btnPress |= buttons;
127 	latch.btnRelease |= ~buttons;
128 	dialogBtnMake |= buttons & changed;
129 	ctrlLatchBufs++;
130 
131 	ctrlOldButtons = buttons;
132 
133 	ctrlBufs[ctrlBuf].frame = (u32)t;
134 	if (!analogEnabled)
135 		memset(ctrlBufs[ctrlBuf].analog, CTRL_ANALOG_CENTER, sizeof(ctrlBufs[ctrlBuf].analog));
136 
137 	ctrlBuf = (ctrlBuf + 1) % NUM_CTRL_BUFFERS;
138 
139 	// If we wrapped around, push the read head forward.
140 	// TODO: Is this right?
141 	if (ctrlBufRead == ctrlBuf)
142 		ctrlBufRead = (ctrlBufRead + 1) % NUM_CTRL_BUFFERS;
143 }
144 
__CtrlResetLatch()145 static int __CtrlResetLatch()
146 {
147 	int oldBufs = ctrlLatchBufs;
148 	memset(&latch, 0, sizeof(CtrlLatch));
149 	ctrlLatchBufs = 0;
150 	return oldBufs;
151 }
152 
__CtrlPeekButtons()153 u32 __CtrlPeekButtons()
154 {
155 	std::lock_guard<std::mutex> guard(ctrlMutex);
156 
157 	return ctrlCurrent.buttons;
158 }
159 
__CtrlPeekAnalog(int stick,float * x,float * y)160 void __CtrlPeekAnalog(int stick, float *x, float *y)
161 {
162 	std::lock_guard<std::mutex> guard(ctrlMutex);
163 
164 	*x = (ctrlCurrent.analog[stick][CTRL_ANALOG_X] - 127.5f) / 127.5f;
165 	*y = -(ctrlCurrent.analog[stick][CTRL_ANALOG_Y] - 127.5f) / 127.5f;
166 }
167 
168 
__CtrlReadLatch()169 u32 __CtrlReadLatch()
170 {
171 	u32 ret = dialogBtnMake;
172 	dialogBtnMake = 0;
173 	return ret;
174 }
175 
176 // Functions so that the rest of the emulator can control what the sceCtrl interface should return
177 // to the game:
178 
__CtrlButtonDown(u32 buttonBit)179 void __CtrlButtonDown(u32 buttonBit)
180 {
181 	std::lock_guard<std::mutex> guard(ctrlMutex);
182 	ctrlCurrent.buttons |= buttonBit;
183 }
184 
__CtrlButtonUp(u32 buttonBit)185 void __CtrlButtonUp(u32 buttonBit)
186 {
187 	std::lock_guard<std::mutex> guard(ctrlMutex);
188 	ctrlCurrent.buttons &= ~buttonBit;
189 }
190 
__CtrlSetAnalogXY(int stick,float x,float y)191 void __CtrlSetAnalogXY(int stick, float x, float y)
192 {
193 	u8 scaledX = clamp_u8((int)ceilf(x * 127.5f + 127.5f));
194 	// TODO: We might have too many negations of Y...
195 	u8 scaledY = clamp_u8((int)ceilf(-y * 127.5f + 127.5f));
196 	std::lock_guard<std::mutex> guard(ctrlMutex);
197 	ctrlCurrent.analog[stick][CTRL_ANALOG_X] = scaledX;
198 	ctrlCurrent.analog[stick][CTRL_ANALOG_Y] = scaledY;
199 }
200 
__CtrlSetRapidFire(bool state)201 void __CtrlSetRapidFire(bool state)
202 {
203 	emuRapidFire = state;
204 }
205 
__CtrlGetRapidFire()206 bool __CtrlGetRapidFire()
207 {
208 	return emuRapidFire;
209 }
210 
__CtrlReadSingleBuffer(PSPPointer<CtrlData> data,bool negative)211 static int __CtrlReadSingleBuffer(PSPPointer<CtrlData> data, bool negative)
212 {
213 	if (data.IsValid())
214 	{
215 		*data = ctrlBufs[ctrlBufRead];
216 		ctrlBufRead = (ctrlBufRead + 1) % NUM_CTRL_BUFFERS;
217 
218 		// Mask out buttons games aren't allowed to see.
219 		data->buttons &= CTRL_MASK_USER;
220 		if (negative)
221 			data->buttons = ~data->buttons;
222 
223 		return 1;
224 	}
225 
226 	return 0;
227 }
228 
__CtrlReadBuffer(u32 ctrlDataPtr,u32 nBufs,bool negative,bool peek)229 static int __CtrlReadBuffer(u32 ctrlDataPtr, u32 nBufs, bool negative, bool peek)
230 {
231 	if (nBufs > NUM_CTRL_BUFFERS)
232 		return SCE_KERNEL_ERROR_INVALID_SIZE;
233 
234 	if (!peek && !__KernelIsDispatchEnabled())
235 		return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
236 	if (!peek && __IsInInterrupt())
237 		return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
238 
239 	u32 resetRead = ctrlBufRead;
240 
241 	u32 availBufs;
242 	// Peeks always work, they just go go from now X buffers.
243 	if (peek)
244 		availBufs = nBufs;
245 	else
246 	{
247 		availBufs = (ctrlBuf - ctrlBufRead + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS;
248 		if (availBufs > nBufs)
249 			availBufs = nBufs;
250 	}
251 	ctrlBufRead = (ctrlBuf - availBufs + NUM_CTRL_BUFFERS) % NUM_CTRL_BUFFERS;
252 
253 	int done = 0;
254 	auto data = PSPPointer<CtrlData>::Create(ctrlDataPtr);
255 	for (u32 i = 0; i < availBufs; ++i)
256 		done += __CtrlReadSingleBuffer(data++, negative);
257 
258 	if (peek)
259 		ctrlBufRead = resetRead;
260 
261 	return done;
262 }
263 
__CtrlDoSample()264 static void __CtrlDoSample()
265 {
266 	// This samples the ctrl data into the buffers and updates the latch.
267 	__CtrlUpdateLatch();
268 
269 	// Wake up a single thread that was waiting for the buffer.
270 retry:
271 	if (!waitingThreads.empty() && ctrlBuf != ctrlBufRead)
272 	{
273 		SceUID threadID = waitingThreads[0];
274 		waitingThreads.erase(waitingThreads.begin());
275 
276 		u32 error;
277 		SceUID wVal = __KernelGetWaitID(threadID, WAITTYPE_CTRL, error);
278 		// Make sure it didn't get woken or something.
279 		if (wVal == 0)
280 			goto retry;
281 
282 		PSPPointer<CtrlData> ctrlDataPtr;
283 		ctrlDataPtr = __KernelGetWaitValue(threadID, error);
284 		int retVal = __CtrlReadSingleBuffer(ctrlDataPtr, wVal == CTRL_WAIT_NEGATIVE);
285 		__KernelResumeThreadFromWait(threadID, retVal);
286 		__KernelReSchedule("ctrl buffers updated");
287 	}
288 }
289 
__CtrlVblank()290 static void __CtrlVblank()
291 {
292 	emuRapidFireFrames++;
293 
294 	// Reduce gamepad Vibration by set % each frame
295 	leftVibration *= (float)vibrationLeftDropout / 256.0f;
296 	rightVibration *= (float)vibrationRightDropout / 256.0f;
297 
298 	// This always runs, so make sure we're in vblank mode.
299 	if (ctrlCycle == 0)
300 		__CtrlDoSample();
301 }
302 
__CtrlTimerUpdate(u64 userdata,int cyclesLate)303 static void __CtrlTimerUpdate(u64 userdata, int cyclesLate)
304 {
305 	// This only runs in timer mode (ctrlCycle > 0.)
306 	_dbg_assert_msg_(ctrlCycle > 0, "Ctrl: sampling cycle should be > 0");
307 
308 	CoreTiming::ScheduleEvent(usToCycles(ctrlCycle) - cyclesLate, ctrlTimer, 0);
309 
310 	__CtrlDoSample();
311 }
312 
__CtrlInit()313 void __CtrlInit()
314 {
315 	ctrlTimer = CoreTiming::RegisterEvent("CtrlSampleTimer", __CtrlTimerUpdate);
316 	__DisplayListenVblank(__CtrlVblank);
317 
318 	ctrlIdleReset = -1;
319 	ctrlIdleBack = -1;
320 	ctrlCycle = 0;
321 
322 	std::lock_guard<std::mutex> guard(ctrlMutex);
323 
324 	ctrlBuf = 1;
325 	ctrlBufRead = 0;
326 	ctrlOldButtons = 0;
327 	ctrlLatchBufs = 0;
328 	dialogBtnMake = 0;
329 
330 	memset(&latch, 0, sizeof(latch));
331 	// Start with everything released.
332 	latch.btnRelease = 0xffffffff;
333 
334 	memset(&ctrlCurrent, 0, sizeof(ctrlCurrent));
335 	memset(ctrlCurrent.analog, CTRL_ANALOG_CENTER, sizeof(ctrlCurrent.analog));
336 	analogEnabled = false;
337 
338 	for (u32 i = 0; i < NUM_CTRL_BUFFERS; i++)
339 		memcpy(&ctrlBufs[i], &ctrlCurrent, sizeof(CtrlData));
340 }
341 
__CtrlDoState(PointerWrap & p)342 void __CtrlDoState(PointerWrap &p)
343 {
344 	std::lock_guard<std::mutex> guard(ctrlMutex);
345 
346 	auto s = p.Section("sceCtrl", 1, 3);
347 	if (!s)
348 		return;
349 
350 	Do(p, analogEnabled);
351 	Do(p, ctrlLatchBufs);
352 	Do(p, ctrlOldButtons);
353 
354 	p.DoVoid(ctrlBufs, sizeof(ctrlBufs));
355 	if (s <= 2) {
356 		CtrlData dummy = {0};
357 		Do(p, dummy);
358 	}
359 	Do(p, ctrlBuf);
360 	Do(p, ctrlBufRead);
361 	Do(p, latch);
362 	if (s == 1) {
363 		dialogBtnMake = 0;
364 	} else {
365 		Do(p, dialogBtnMake);
366 	}
367 
368 	Do(p, ctrlIdleReset);
369 	Do(p, ctrlIdleBack);
370 
371 	Do(p, ctrlCycle);
372 
373 	SceUID dv = 0;
374 	Do(p, waitingThreads, dv);
375 
376 	Do(p, ctrlTimer);
377 	CoreTiming::RestoreRegisterEvent(ctrlTimer, "CtrlSampleTimer", __CtrlTimerUpdate);
378 }
379 
__CtrlShutdown()380 void __CtrlShutdown()
381 {
382 	waitingThreads.clear();
383 }
384 
sceCtrlSetSamplingCycle(u32 cycle)385 static u32 sceCtrlSetSamplingCycle(u32 cycle)
386 {
387 	DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingCycle(%u)", cycle);
388 
389 	if ((cycle > 0 && cycle < 5555) || cycle > 20000)
390 	{
391 		WARN_LOG(SCECTRL, "SCE_KERNEL_ERROR_INVALID_VALUE=sceCtrlSetSamplingCycle(%u)", cycle);
392 		return SCE_KERNEL_ERROR_INVALID_VALUE;
393 	}
394 
395 	u32 prev = ctrlCycle;
396 	ctrlCycle = cycle;
397 
398 	if (prev > 0)
399 		CoreTiming::UnscheduleEvent(ctrlTimer, 0);
400 	if (cycle > 0)
401 		CoreTiming::ScheduleEvent(usToCycles(ctrlCycle), ctrlTimer, 0);
402 
403 	return prev;
404 }
405 
sceCtrlGetSamplingCycle(u32 cyclePtr)406 static int sceCtrlGetSamplingCycle(u32 cyclePtr)
407 {
408 	DEBUG_LOG(SCECTRL, "sceCtrlGetSamplingCycle(%08x)", cyclePtr);
409 	if (Memory::IsValidAddress(cyclePtr))
410 		Memory::Write_U32(ctrlCycle, cyclePtr);
411 	return 0;
412 }
413 
sceCtrlSetSamplingMode(u32 mode)414 static u32 sceCtrlSetSamplingMode(u32 mode)
415 {
416 	u32 retVal = 0;
417 
418 	DEBUG_LOG(SCECTRL, "sceCtrlSetSamplingMode(%i)", mode);
419 	if (mode > 1)
420 		return SCE_KERNEL_ERROR_INVALID_MODE;
421 
422 	retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
423 	analogEnabled = mode == CTRL_MODE_ANALOG ? true : false;
424 	return retVal;
425 }
426 
sceCtrlGetSamplingMode(u32 modePtr)427 static int sceCtrlGetSamplingMode(u32 modePtr)
428 {
429 	u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL;
430 	DEBUG_LOG(SCECTRL, "%d=sceCtrlGetSamplingMode(%08x)", retVal, modePtr);
431 
432 	if (Memory::IsValidAddress(modePtr))
433 		Memory::Write_U32(retVal, modePtr);
434 
435 	return 0;
436 }
437 
sceCtrlSetIdleCancelThreshold(int idleReset,int idleBack)438 static int sceCtrlSetIdleCancelThreshold(int idleReset, int idleBack)
439 {
440 	DEBUG_LOG(SCECTRL, "FAKE sceCtrlSetIdleCancelThreshold(%d, %d)", idleReset, idleBack);
441 
442 	if (idleReset < -1 || idleBack < -1 || idleReset > 128 || idleBack > 128)
443 		return SCE_KERNEL_ERROR_INVALID_VALUE;
444 
445 	ctrlIdleReset = idleReset;
446 	ctrlIdleBack = idleBack;
447 	return 0;
448 }
449 
sceCtrlGetIdleCancelThreshold(u32 idleResetPtr,u32 idleBackPtr)450 static int sceCtrlGetIdleCancelThreshold(u32 idleResetPtr, u32 idleBackPtr)
451 {
452 	DEBUG_LOG(SCECTRL, "sceCtrlSetIdleCancelThreshold(%08x, %08x)", idleResetPtr, idleBackPtr);
453 
454 	if (idleResetPtr && !Memory::IsValidAddress(idleResetPtr))
455 		return SCE_KERNEL_ERROR_PRIV_REQUIRED;
456 	if (idleBackPtr && !Memory::IsValidAddress(idleBackPtr))
457 		return SCE_KERNEL_ERROR_PRIV_REQUIRED;
458 
459 	if (idleResetPtr)
460 		Memory::Write_U32(ctrlIdleReset, idleResetPtr);
461 	if (idleBackPtr)
462 		Memory::Write_U32(ctrlIdleBack, idleBackPtr);
463 
464 	return 0;
465 }
466 
sceCtrlReadBufferPositive(u32 ctrlDataPtr,u32 nBufs)467 static int sceCtrlReadBufferPositive(u32 ctrlDataPtr, u32 nBufs)
468 {
469 	int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, false, false);
470 	hleEatCycles(330);
471 	if (done != 0)
472 	{
473 		DEBUG_LOG(SCECTRL, "%d=sceCtrlReadBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs);
474 	}
475 	else
476 	{
477 		waitingThreads.push_back(__KernelGetCurThread());
478 		__KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_POSITIVE, ctrlDataPtr, 0, false, "ctrl buffer waited");
479 		DEBUG_LOG(SCECTRL, "sceCtrlReadBufferPositive(%08x, %i) - waiting", ctrlDataPtr, nBufs);
480 	}
481 	return done;
482 }
483 
sceCtrlReadBufferNegative(u32 ctrlDataPtr,u32 nBufs)484 static int sceCtrlReadBufferNegative(u32 ctrlDataPtr, u32 nBufs)
485 {
486 	int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, true, false);
487 	hleEatCycles(330);
488 	if (done != 0)
489 	{
490 		DEBUG_LOG(SCECTRL, "%d=sceCtrlReadBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs);
491 	}
492 	else
493 	{
494 		waitingThreads.push_back(__KernelGetCurThread());
495 		__KernelWaitCurThread(WAITTYPE_CTRL, CTRL_WAIT_NEGATIVE, ctrlDataPtr, 0, false, "ctrl buffer waited");
496 		DEBUG_LOG(SCECTRL, "sceCtrlReadBufferNegative(%08x, %i) - waiting", ctrlDataPtr, nBufs);
497 	}
498 	return done;
499 }
500 
sceCtrlPeekBufferPositive(u32 ctrlDataPtr,u32 nBufs)501 static int sceCtrlPeekBufferPositive(u32 ctrlDataPtr, u32 nBufs)
502 {
503 	int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, false, true);
504 	// Some homebrew call this in a tight loop - so VERBOSE it is.
505 	VERBOSE_LOG(SCECTRL, "%d=sceCtrlPeekBufferPositive(%08x, %i)", done, ctrlDataPtr, nBufs);
506 	hleEatCycles(330);
507 	return done;
508 }
509 
sceCtrlPeekBufferNegative(u32 ctrlDataPtr,u32 nBufs)510 static int sceCtrlPeekBufferNegative(u32 ctrlDataPtr, u32 nBufs)
511 {
512 	int done = __CtrlReadBuffer(ctrlDataPtr, nBufs, true, true);
513 	// Some homebrew call this in a tight loop - so VERBOSE it is.
514 	VERBOSE_LOG(SCECTRL, "%d=sceCtrlPeekBufferNegative(%08x, %i)", done, ctrlDataPtr, nBufs);
515 	hleEatCycles(330);
516 	return done;
517 }
518 
__CtrlWriteUserLatch(CtrlLatch * userLatch,int bufs)519 static void __CtrlWriteUserLatch(CtrlLatch *userLatch, int bufs) {
520 	*userLatch = latch;
521 	userLatch->btnBreak &= CTRL_MASK_USER;
522 	userLatch->btnMake &= CTRL_MASK_USER;
523 	userLatch->btnPress &= CTRL_MASK_USER;
524 	if (bufs > 0) {
525 		userLatch->btnRelease |= ~CTRL_MASK_USER;
526 	}
527 }
528 
sceCtrlPeekLatch(u32 latchDataPtr)529 static u32 sceCtrlPeekLatch(u32 latchDataPtr) {
530 	auto userLatch = PSPPointer<CtrlLatch>::Create(latchDataPtr);
531 	if (userLatch.IsValid()) {
532 		__CtrlWriteUserLatch(userLatch, ctrlLatchBufs);
533 	}
534 	return hleLogSuccessI(SCECTRL, ctrlLatchBufs);
535 }
536 
sceCtrlReadLatch(u32 latchDataPtr)537 static u32 sceCtrlReadLatch(u32 latchDataPtr) {
538 	auto userLatch = PSPPointer<CtrlLatch>::Create(latchDataPtr);
539 	if (userLatch.IsValid()) {
540 		__CtrlWriteUserLatch(userLatch, ctrlLatchBufs);
541 	}
542 	return hleLogSuccessI(SCECTRL, __CtrlResetLatch());
543 }
544 
545 static const HLEFunction sceCtrl[] =
546 {
547 	{0X3E65A0EA, nullptr,                                  "sceCtrlInit",                      '?', ""  }, //(int unknown), init with 0
548 	{0X1F4011E6, &WrapU_U<sceCtrlSetSamplingMode>,         "sceCtrlSetSamplingMode",           'x', "x" },
549 	{0X6A2774F3, &WrapU_U<sceCtrlSetSamplingCycle>,        "sceCtrlSetSamplingCycle",          'x', "x" },
550 	{0X02BAAD91, &WrapI_U<sceCtrlGetSamplingCycle>,        "sceCtrlGetSamplingCycle",          'i', "x" },
551 	{0XDA6B76A1, &WrapI_U<sceCtrlGetSamplingMode>,         "sceCtrlGetSamplingMode",           'i', "x" },
552 	{0X1F803938, &WrapI_UU<sceCtrlReadBufferPositive>,     "sceCtrlReadBufferPositive",        'i', "xx"},
553 	{0X3A622550, &WrapI_UU<sceCtrlPeekBufferPositive>,     "sceCtrlPeekBufferPositive",        'i', "xx"},
554 	{0XC152080A, &WrapI_UU<sceCtrlPeekBufferNegative>,     "sceCtrlPeekBufferNegative",        'i', "xx"},
555 	{0X60B81F86, &WrapI_UU<sceCtrlReadBufferNegative>,     "sceCtrlReadBufferNegative",        'i', "xx"},
556 	{0XB1D0E5CD, &WrapU_U<sceCtrlPeekLatch>,               "sceCtrlPeekLatch",                 'i', "x" },
557 	{0X0B588501, &WrapU_U<sceCtrlReadLatch>,               "sceCtrlReadLatch",                 'i', "x" },
558 	{0X348D99D4, nullptr,                                  "sceCtrlSetSuspendingExtraSamples", '?', ""  },
559 	{0XAF5960F3, nullptr,                                  "sceCtrlGetSuspendingExtraSamples", '?', ""  },
560 	{0XA68FD260, nullptr,                                  "sceCtrlClearRapidFire",            '?', ""  },
561 	{0X6841BE1A, nullptr,                                  "sceCtrlSetRapidFire",              '?', ""  },
562 	{0XA7144800, &WrapI_II<sceCtrlSetIdleCancelThreshold>, "sceCtrlSetIdleCancelThreshold",    'i', "ii"},
563 	{0X687660FA, &WrapI_UU<sceCtrlGetIdleCancelThreshold>, "sceCtrlGetIdleCancelThreshold",    'i', "xx"},
564 };
565 
Register_sceCtrl()566 void Register_sceCtrl()
567 {
568 	RegisterModule("sceCtrl", ARRAY_SIZE(sceCtrl), sceCtrl);
569 }
570 
Register_sceCtrl_driver()571 void Register_sceCtrl_driver()
572 {
573 	RegisterModule("sceCtrl_driver", ARRAY_SIZE(sceCtrl), sceCtrl);
574 }
575 
sceCtrlGetRightVibration()576 u16 sceCtrlGetRightVibration() {
577 	return rightVibration;
578 }
579 
sceCtrlGetLeftVibration()580 u16 sceCtrlGetLeftVibration() {
581 	return leftVibration;
582 }
583 
584 namespace SceCtrl {
SetRightVibration(u16 rVibration)585 	void SetRightVibration(u16 rVibration) {
586 		rightVibration = rVibration;
587 	}
SetLeftVibration(u16 lVibration)588 	void SetLeftVibration(u16 lVibration) {
589 		leftVibration = lVibration;
590 	}
SetVibrationRightDropout(u8 vibrationRDropout)591 	void SetVibrationRightDropout(u8 vibrationRDropout) {
592 		vibrationRightDropout = vibrationRDropout;
593 	}
SetVibrationLeftDropout(u8 vibrationLDropout)594 	void SetVibrationLeftDropout(u8 vibrationLDropout) {
595 		vibrationLeftDropout = vibrationLDropout;
596 	}
597 }
598