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 #include <map>
18 #include <vector>
19 #include "Common/Serialize/Serializer.h"
20 #include "Common/Serialize/SerializeFuncs.h"
21 #include "Core/HLE/HLE.h"
22 #include "Core/HLE/FunctionWrappers.h"
23 #include "Core/CoreTiming.h"
24 #include "Core/MemMap.h"
25 #include "Core/Reporting.h"
26 #include "Core/Config.h"
27 
28 #include "Core/HLE/scePower.h"
29 #include "Core/HLE/sceKernelThread.h"
30 #include "Core/HLE/sceKernelInterrupt.h"
31 
32 struct VolatileWaitingThread {
33 	SceUID threadID;
34 	u32 addrPtr;
35 	u32 sizePtr;
36 };
37 
38 const int PSP_POWER_ERROR_TAKEN_SLOT = 0x80000020;
39 const int PSP_POWER_ERROR_SLOTS_FULL = 0x80000022;
40 const int PSP_POWER_ERROR_EMPTY_SLOT = 0x80000025;
41 const int PSP_POWER_ERROR_INVALID_CB = 0x80000100;
42 const int PSP_POWER_ERROR_INVALID_SLOT = 0x80000102;
43 
44 const int PSP_POWER_CB_AC_POWER = 0x00001000;
45 const int PSP_POWER_CB_BATTERY_EXIST = 0x00000080;
46 const int PSP_POWER_CB_BATTERY_FULL = 0x00000064;
47 
48 const int POWER_CB_AUTO = -1;
49 
50 // These are the callback slots for user mode applications.
51 const int numberOfCBPowerSlots = 16;
52 
53 // These are the callback slots for kernel mode applications.
54 const int numberOfCBPowerSlotsPrivate = 32;
55 
56 static bool volatileMemLocked;
57 static int powerCbSlots[numberOfCBPowerSlots];
58 static std::vector<VolatileWaitingThread> volatileWaitingThreads;
59 
60 // Should this belong here, or in CoreTiming?
61 static int RealpllFreq = 222000000;
62 static int RealbusFreq = 111000000;
63 static int pllFreq = 222000000;
64 static int busFreq = 111000000;
65 
66 // The CPU mhz can only be a multiple of the PLL divided by 511.
PowerCpuMhzToHz(int desired,int pllHz)67 int PowerCpuMhzToHz(int desired, int pllHz) {
68 	double maxfreq = desired * 1000000.0;
69 
70 	double step = (double)pllHz / 511.0;
71 	// These values seem to be locked.
72 	if (pllHz >= 333000000 && desired == 333) {
73 		return 333000000;
74 	}  else if (pllHz >= 222000000 && desired == 222) {
75 		return 222000000;
76 	}
77 
78 	double freq = 0;
79 	while (freq + step < maxfreq) {
80 		freq += step;
81 	}
82 
83 	// We match the PSP's HLE funcs better when we have the same float error, it seems.
84 	return (float)(freq / 1000000.0f) * 1000000;
85 }
86 
PowerPllMhzToHz(int mhz)87 int PowerPllMhzToHz(int mhz) {
88 	// These seem to be the only steps it has.
89 	if (mhz <= 190)
90 		return 190285721;
91 	if (mhz <= 222)
92 		return 222000000;
93 	if (mhz <= 266)
94 		return 266399994;
95 	if (mhz <= 333)
96 		return 333000000;
97 	return mhz * 1000000;
98 }
99 
PowerBusMhzToHz(int mhz)100 int PowerBusMhzToHz(int mhz) {
101 	// These seem to be the only steps it has.
102 	if (mhz <= 95)
103 		return 95142860;
104 	if (mhz <= 111)
105 		return 111000000;
106 	if (mhz <= 133)
107 		return 133199997;
108 	if (mhz <= 166)
109 		return 166500000;
110 	return mhz * 1000000;
111 }
112 
__PowerInit()113 void __PowerInit() {
114 	memset(powerCbSlots, 0, sizeof(powerCbSlots));
115 	volatileMemLocked = false;
116 	volatileWaitingThreads.clear();
117 
118 	if (g_Config.iLockedCPUSpeed > 0) {
119 		pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
120 		busFreq = PowerBusMhzToHz(pllFreq / 2000000);
121 		CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
122 	} else {
123 		pllFreq = PowerPllMhzToHz(222);
124 		busFreq = PowerBusMhzToHz(111);
125 	}
126 	RealpllFreq = PowerPllMhzToHz(222);
127 	RealbusFreq = PowerBusMhzToHz(111);
128 }
129 
__PowerDoState(PointerWrap & p)130 void __PowerDoState(PointerWrap &p) {
131 	auto s = p.Section("scePower",1,2);
132 	if (!s)
133 		return;
134 
135 	if (s >= 2) {
136 		Do(p, RealpllFreq);
137 		Do(p, RealbusFreq);
138 
139 		if (RealpllFreq < 1000000)
140 			RealpllFreq = PowerPllMhzToHz(RealpllFreq);
141 		if (RealbusFreq < 1000000)
142 			RealbusFreq = PowerBusMhzToHz(RealbusFreq);
143 	} else {
144 		RealpllFreq = PowerPllMhzToHz(222);
145 		RealbusFreq = PowerBusMhzToHz(111);
146 	}
147 	if (g_Config.iLockedCPUSpeed > 0) {
148 		pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
149 		busFreq = PowerBusMhzToHz(pllFreq / 2000000);
150 		CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
151 	} else {
152 		pllFreq = RealpllFreq;
153 		busFreq = RealbusFreq;
154 	}
155 	DoArray(p, powerCbSlots, ARRAY_SIZE(powerCbSlots));
156 	Do(p, volatileMemLocked);
157 	Do(p, volatileWaitingThreads);
158 }
159 
scePowerGetBatteryLifePercent()160 static int scePowerGetBatteryLifePercent() {
161 	DEBUG_LOG(HLE, "100=scePowerGetBatteryLifePercent");
162 	return 100;
163 }
164 
scePowerGetBatteryLifeTime()165 static int scePowerGetBatteryLifeTime() {
166 	DEBUG_LOG(HLE, "0=scePowerGetBatteryLifeTime()");
167 	// 0 means we're on AC power.
168 	return 0;
169 }
170 
scePowerGetBatteryTemp()171 static int scePowerGetBatteryTemp() {
172 	DEBUG_LOG(HLE, "0=scePowerGetBatteryTemp()");
173 	// 0 means celsius temperature of the battery
174 	return 0;
175 }
176 
scePowerIsPowerOnline()177 static int scePowerIsPowerOnline() {
178 	DEBUG_LOG(HLE, "1=scePowerIsPowerOnline");
179 	return 1;
180 }
181 
scePowerIsBatteryExist()182 static int scePowerIsBatteryExist() {
183 	DEBUG_LOG(HLE, "1=scePowerIsBatteryExist");
184 	return 1;
185 }
186 
scePowerIsBatteryCharging()187 static int scePowerIsBatteryCharging() {
188 	DEBUG_LOG(HLE, "0=scePowerIsBatteryCharging");
189 	return 0;
190 }
191 
scePowerGetBatteryChargingStatus()192 static int scePowerGetBatteryChargingStatus() {
193 	DEBUG_LOG(HLE, "0=scePowerGetBatteryChargingStatus");
194 	return 0;
195 }
196 
scePowerIsLowBattery()197 static int scePowerIsLowBattery() {
198 	DEBUG_LOG(HLE, "0=scePowerIsLowBattery");
199 	return 0;
200 }
201 
scePowerRegisterCallback(int slot,int cbId)202 static int scePowerRegisterCallback(int slot, int cbId) {
203 	DEBUG_LOG(HLE, "0=scePowerRegisterCallback(%i, %i)", slot, cbId);
204 
205 	if (slot < -1 || slot >= numberOfCBPowerSlotsPrivate) {
206 		return PSP_POWER_ERROR_INVALID_SLOT;
207 	}
208 	if (slot >= numberOfCBPowerSlots) {
209 		return SCE_KERNEL_ERROR_PRIV_REQUIRED;
210 	}
211 	// TODO: If cbId is invalid return PSP_POWER_ERROR_INVALID_CB.
212 	if (cbId == 0) {
213 		return PSP_POWER_ERROR_INVALID_CB;
214 	}
215 
216 	int retval = -1;
217 
218 	if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank
219 		for (int i=0; i < numberOfCBPowerSlots; i++) {
220 			if (powerCbSlots[i] == 0 && retval == -1) { // found an empty slot
221 				powerCbSlots[i] = cbId;
222 				retval = i;
223 			}
224 		}
225 		if (retval == -1) {
226 			return PSP_POWER_ERROR_SLOTS_FULL;
227 		}
228 	} else {
229 		if (powerCbSlots[slot] == 0) {
230 			powerCbSlots[slot] = cbId;
231 			retval = 0;
232 		} else {
233 			return PSP_POWER_ERROR_TAKEN_SLOT;
234 		}
235 	}
236 	if (retval >= 0) {
237 		int arg = PSP_POWER_CB_AC_POWER | PSP_POWER_CB_BATTERY_EXIST | PSP_POWER_CB_BATTERY_FULL;
238 		__KernelNotifyCallback(cbId, arg);
239 	}
240 	return retval;
241 }
242 
scePowerUnregisterCallback(int slotId)243 static int scePowerUnregisterCallback(int slotId) {
244 	DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i)", slotId);
245 
246 	if (slotId < 0 || slotId >= numberOfCBPowerSlotsPrivate) {
247 		return PSP_POWER_ERROR_INVALID_SLOT;
248 	}
249 	if (slotId >= numberOfCBPowerSlots) {
250 		return SCE_KERNEL_ERROR_PRIV_REQUIRED;
251 	}
252 
253 	if (powerCbSlots[slotId] != 0) {
254 		int cbId = powerCbSlots[slotId];
255 		DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId);
256 		powerCbSlots[slotId] = 0;
257 	} else {
258 		return PSP_POWER_ERROR_EMPTY_SLOT;
259 	}
260 
261 	return 0;
262 }
263 
sceKernelPowerLock(int lockType)264 static int sceKernelPowerLock(int lockType) {
265 	DEBUG_LOG(HLE, "0=sceKernelPowerLock(%i)", lockType);
266 	if (lockType == 0) {
267 		return 0;
268 	} else {
269 		return SCE_KERNEL_ERROR_INVALID_MODE;
270 	}
271 }
272 
sceKernelPowerUnlock(int lockType)273 static int sceKernelPowerUnlock(int lockType) {
274 	DEBUG_LOG(HLE, "0=sceKernelPowerUnlock(%i)", lockType);
275 	if (lockType == 0) {
276 		return 0;
277 	} else {
278 		return SCE_KERNEL_ERROR_INVALID_MODE;
279 	}
280 }
281 
sceKernelPowerTick(int flag)282 static int sceKernelPowerTick(int flag) {
283 	DEBUG_LOG(HLE, "UNIMPL 0=sceKernelPowerTick(%i)", flag);
284 	return 0;
285 }
286 
KernelVolatileMemLock(int type,u32 paddr,u32 psize)287 int KernelVolatileMemLock(int type, u32 paddr, u32 psize) {
288 	if (type != 0) {
289 		return SCE_KERNEL_ERROR_INVALID_MODE;
290 	}
291 	if (volatileMemLocked) {
292 		return SCE_KERNEL_ERROR_POWER_VMEM_IN_USE;
293 	}
294 
295 	// Volatile RAM is always at 0x08400000 and is of size 0x00400000.
296 	// It's always available in the emu.
297 	// TODO: Should really reserve this properly!
298 	if (Memory::IsValidAddress(paddr)) {
299 		Memory::Write_U32(0x08400000, paddr);
300 	}
301 	if (Memory::IsValidAddress(psize)) {
302 		Memory::Write_U32(0x00400000, psize);
303 	}
304 	volatileMemLocked = true;
305 
306 	return 0;
307 }
308 
sceKernelVolatileMemTryLock(int type,u32 paddr,u32 psize)309 static int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) {
310 	u32 error = KernelVolatileMemLock(type, paddr, psize);
311 
312 	switch (error) {
313 	case 0:
314 		// HACK: This fixes Crash Tag Team Racing.
315 		// Should only wait 1200 cycles though according to Unknown's testing,
316 		// and with that it's still broken. So it's not this, unfortunately.
317 		// Leaving it in for the 0.9.8 release anyway.
318 		hleEatCycles(500000);
319 		DEBUG_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize);
320 		break;
321 
322 	case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE:
323 		ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize);
324 		break;
325 
326 	default:
327 		ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error);
328 		break;
329 	}
330 
331 	return error;
332 }
333 
KernelVolatileMemUnlock(int type)334 int KernelVolatileMemUnlock(int type) {
335 	if (type != 0) {
336 		return SCE_KERNEL_ERROR_INVALID_MODE;
337 	}
338 	if (!volatileMemLocked) {
339 		// I guess it must use a sema.
340 		return SCE_KERNEL_ERROR_SEMA_OVF;
341 	}
342 
343 	volatileMemLocked = false;
344 
345 	// Wake someone, always fifo.
346 	bool wokeThreads = false;
347 	u32 error;
348 	while (!volatileWaitingThreads.empty() && !volatileMemLocked) {
349 		VolatileWaitingThread waitInfo = volatileWaitingThreads.front();
350 		volatileWaitingThreads.erase(volatileWaitingThreads.begin());
351 
352 		int waitID = __KernelGetWaitID(waitInfo.threadID, WAITTYPE_VMEM, error);
353 		// If they were force-released, just skip.
354 		if (waitID == 1 && KernelVolatileMemLock(0, waitInfo.addrPtr, waitInfo.sizePtr) == 0) {
355 			__KernelResumeThreadFromWait(waitInfo.threadID, 0);
356 			wokeThreads = true;
357 		}
358 	}
359 
360 	if (wokeThreads) {
361 		INFO_LOG(HLE, "KernelVolatileMemUnlock(%i) handed over to another thread", type);
362 		hleReSchedule("volatile mem unlocked");
363 	}
364 	return 0;
365 }
366 
sceKernelVolatileMemUnlock(int type)367 static int sceKernelVolatileMemUnlock(int type) {
368 	int error = KernelVolatileMemUnlock(type);
369 	if (error == SCE_KERNEL_ERROR_INVALID_MODE) {
370 		ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type);
371 		return error;
372 	} else if (error == SCE_KERNEL_ERROR_SEMA_OVF) {
373 		ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type);
374 		return error;
375 	}
376 
377 	return hleLogSuccessI(HLE, 0);
378 }
379 
sceKernelVolatileMemLock(int type,u32 paddr,u32 psize)380 static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) {
381 	u32 error = 0;
382 
383 	// If dispatch is disabled or in an interrupt, don't check, just return an error.
384 	// But still write the addr and size (some games require this to work, and it's testably true.)
385 	if (!__KernelIsDispatchEnabled()) {
386 		error = SCE_KERNEL_ERROR_CAN_NOT_WAIT;
387 	} else if (__IsInInterrupt()) {
388 		error = SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
389 	} else {
390 		error = KernelVolatileMemLock(type, paddr, psize);
391 	}
392 
393 	switch (error) {
394 	case 0:
395 		// Should only wait 1200 cycles though according to Unknown's testing,
396 		hleEatCycles(1200);
397 		DEBUG_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize);
398 		break;
399 
400 	case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE:
401 		{
402 			WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize);
403 			const VolatileWaitingThread waitInfo = { __KernelGetCurThread(), paddr, psize };
404 			volatileWaitingThreads.push_back(waitInfo);
405 			__KernelWaitCurThread(WAITTYPE_VMEM, 1, 0, 0, false, "volatile mem waited");
406 		}
407 		break;
408 
409 	case SCE_KERNEL_ERROR_CAN_NOT_WAIT:
410 		{
411 			WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled", type, paddr, psize);
412 			Memory::Write_U32(0x08400000, paddr);
413 			Memory::Write_U32(0x00400000, psize);
414 		}
415 		break;
416 
417 	case SCE_KERNEL_ERROR_ILLEGAL_CONTEXT:
418 		{
419 			WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt", type, paddr, psize);
420 			Memory::Write_U32(0x08400000, paddr);
421 			Memory::Write_U32(0x00400000, psize);
422 		}
423 		break;
424 
425 	default:
426 		ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error);
427 		break;
428 	}
429 
430 	return error;
431 }
432 
433 
scePowerSetClockFrequency(u32 pllfreq,u32 cpufreq,u32 busfreq)434 static u32 scePowerSetClockFrequency(u32 pllfreq, u32 cpufreq, u32 busfreq) {
435 	// 190 might (probably) be a typo for 19, but it's what the actual PSP validates against.
436 	if (pllfreq < 19 || pllfreq < cpufreq || pllfreq > 333) {
437 		return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid pll frequency");
438 	}
439 	if (cpufreq == 0 || cpufreq > 333) {
440 		return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid cpu frequency");
441 	}
442 	if (busfreq == 0 || busfreq > 166) {
443 		return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid bus frequency");
444 	}
445 	// TODO: More restrictions.
446 	if (g_Config.iLockedCPUSpeed > 0) {
447 		INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i): locked by user config at %i, %i, %i", pllfreq, cpufreq, busfreq, g_Config.iLockedCPUSpeed, g_Config.iLockedCPUSpeed, busFreq);
448 	} else {
449 		INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i)", pllfreq, cpufreq, busfreq);
450 	}
451 	// Only reschedules when the stepped PLL frequency changes.
452 	// It seems like the busfreq parameter has no effect (but can cause errors.)
453 	if (RealpllFreq != PowerPllMhzToHz(pllfreq)) {
454 		int oldPll = RealpllFreq / 1000000;
455 
456 		RealpllFreq = PowerPllMhzToHz(pllfreq);
457 		RealbusFreq = PowerBusMhzToHz(RealpllFreq / 2000000);
458 		if (g_Config.iLockedCPUSpeed <= 0) {
459 			pllFreq = RealpllFreq;
460 			busFreq = RealbusFreq;
461 			CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
462 		}
463 
464 		// The delay depends on the source and destination frequency, most are 150ms.
465 		int newPll = RealpllFreq / 1000000;
466 		int usec = 150000;
467 		if ((newPll == 190 && oldPll == 222) || (newPll == 222 && oldPll == 190))
468 			usec = 15700;
469 		else if ((newPll == 266 && oldPll == 333) || (newPll == 333 && oldPll == 266))
470 			usec = 16600;
471 
472 		return hleDelayResult(0, "scepower set clockFrequency", usec);
473 	}
474 	if (g_Config.iLockedCPUSpeed <= 0)
475 		CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
476 	return 0;
477 }
478 
scePowerSetCpuClockFrequency(u32 cpufreq)479 static u32 scePowerSetCpuClockFrequency(u32 cpufreq) {
480 	if (cpufreq == 0 || cpufreq > 333) {
481 		return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
482 	}
483 	if (g_Config.iLockedCPUSpeed > 0) {
484 		return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed);
485 	}
486 	CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
487 	return hleLogSuccessI(SCEMISC, 0);
488 }
489 
scePowerSetBusClockFrequency(u32 busfreq)490 static u32 scePowerSetBusClockFrequency(u32 busfreq) {
491 	if (busfreq == 0 || busfreq > 111) {
492 		return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
493 	}
494 	if (g_Config.iLockedCPUSpeed > 0) {
495 		return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed / 2);
496 	}
497 
498 	// The value passed is validated, but then doesn't seem to matter for the result.
499 	// However, this sets a different hz than scePowerSetClockFrequency would have.
500 
501 	if (pllFreq <= 190)
502 		busFreq = 94956673;
503 	else if (pllFreq <= 222)
504 		busFreq = 111000000;
505 	else if (pllFreq <= 266)
506 		busFreq = 132939331;
507 	else if (pllFreq <= 333)
508 		busFreq = 165848343;
509 	else
510 		busFreq = pllFreq / 2;
511 
512 	return hleLogSuccessI(SCEMISC, 0);
513 }
514 
scePowerGetCpuClockFrequencyInt()515 static u32 scePowerGetCpuClockFrequencyInt() {
516 	int cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000;
517 	return hleLogSuccessI(SCEMISC, cpuFreq);
518 }
519 
scePowerGetPllClockFrequencyInt()520 static u32 scePowerGetPllClockFrequencyInt() {
521 	return hleLogSuccessInfoI(SCEMISC, pllFreq / 1000000);
522 }
523 
scePowerGetBusClockFrequencyInt()524 static u32 scePowerGetBusClockFrequencyInt() {
525 	return hleLogSuccessInfoI(SCEMISC, busFreq / 1000000);
526 }
527 
scePowerGetCpuClockFrequencyFloat()528 static float scePowerGetCpuClockFrequencyFloat() {
529 	float cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000.0f;
530 	DEBUG_LOG(SCEMISC, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq);
531 	return cpuFreq;
532 }
533 
scePowerGetPllClockFrequencyFloat()534 static float scePowerGetPllClockFrequencyFloat() {
535 	INFO_LOG(SCEMISC, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq / 1000000.0f);
536 	return (float) pllFreq / 1000000.0f;
537 }
538 
scePowerGetBusClockFrequencyFloat()539 static float scePowerGetBusClockFrequencyFloat() {
540 	INFO_LOG(SCEMISC, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq / 1000000.0f);
541 	return (float) busFreq / 1000000.0f;
542 }
543 
scePowerTick()544 static int scePowerTick() {
545 	DEBUG_LOG(SCEMISC, "scePowerTick()");
546 	// Don't think we need to do anything.
547 	return 0;
548 }
549 
550 
IsPSPNonFat()551 static u32 IsPSPNonFat() {
552 	DEBUG_LOG(SCEMISC, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel);
553 
554 	return g_Config.iPSPModel;
555 }
556 
557 static const HLEFunction scePower[] = {
558 	{0X04B7766E, &WrapI_II<scePowerRegisterCallback>,         "scePowerRegisterCallback",          'i', "ii" },
559 	{0X2B51FE2F, nullptr,                                     "scePower_2B51FE2F",                 '?', ""   },
560 	{0X442BFBAC, nullptr,                                     "scePowerGetBacklightMaximum",       '?', ""   },
561 	{0XEFD3C963, &WrapI_V<scePowerTick>,                      "scePowerTick",                      'i', ""   },
562 	{0XEDC13FE5, nullptr,                                     "scePowerGetIdleTimer",              '?', ""   },
563 	{0X7F30B3B1, nullptr,                                     "scePowerIdleTimerEnable",           '?', ""   },
564 	{0X972CE941, nullptr,                                     "scePowerIdleTimerDisable",          '?', ""   },
565 	{0X27F3292C, nullptr,                                     "scePowerBatteryUpdateInfo",         '?', ""   },
566 	{0XE8E4E204, nullptr,                                     "scePower_E8E4E204",                 '?', ""   },
567 	{0XB999184C, nullptr,                                     "scePowerGetLowBatteryCapacity",     '?', ""   },
568 	{0X87440F5E, &WrapI_V<scePowerIsPowerOnline>,             "scePowerIsPowerOnline",             'i', ""   },
569 	{0X0AFD0D8B, &WrapI_V<scePowerIsBatteryExist>,            "scePowerIsBatteryExist",            'i', ""   },
570 	{0X1E490401, &WrapI_V<scePowerIsBatteryCharging>,         "scePowerIsBatteryCharging",         'i', ""   },
571 	{0XB4432BC8, &WrapI_V<scePowerGetBatteryChargingStatus>,  "scePowerGetBatteryChargingStatus",  'i', ""   },
572 	{0XD3075926, &WrapI_V<scePowerIsLowBattery>,              "scePowerIsLowBattery",              'i', ""   },
573 	{0X78A1A796, nullptr,                                     "scePowerIsSuspendRequired",         '?', ""   },
574 	{0X94F5A53F, nullptr,                                     "scePowerGetBatteryRemainCapacity",  '?', ""   },
575 	{0XFD18A0FF, nullptr,                                     "scePowerGetBatteryFullCapacity",    '?', ""   },
576 	{0X2085D15D, &WrapI_V<scePowerGetBatteryLifePercent>,     "scePowerGetBatteryLifePercent",     'i', ""   },
577 	{0X8EFB3FA2, &WrapI_V<scePowerGetBatteryLifeTime>,        "scePowerGetBatteryLifeTime",        'i', ""   },
578 	{0X28E12023, &WrapI_V<scePowerGetBatteryTemp>,            "scePowerGetBatteryTemp",            'i', ""   },
579 	{0X862AE1A6, nullptr,                                     "scePowerGetBatteryElec",            '?', ""   },
580 	{0X483CE86B, nullptr,                                     "scePowerGetBatteryVolt",            '?', ""   },
581 	{0XCB49F5CE, nullptr,                                     "scePowerGetBatteryChargeCycle",     '?', ""   },
582 	{0X23436A4A, nullptr,                                     "scePowerGetInnerTemp",              '?', ""   },
583 	{0X0CD21B1F, nullptr,                                     "scePowerSetPowerSwMode",            '?', ""   },
584 	{0X165CE085, nullptr,                                     "scePowerGetPowerSwMode",            '?', ""   },
585 	{0XD6D016EF, nullptr,                                     "scePowerLock",                      '?', ""   },
586 	{0XCA3D34C1, nullptr,                                     "scePowerUnlock",                    '?', ""   },
587 	{0XDB62C9CF, nullptr,                                     "scePowerCancelRequest",             '?', ""   },
588 	{0X7FA406DD, nullptr,                                     "scePowerIsRequest",                 '?', ""   },
589 	{0X2B7C7CF4, nullptr,                                     "scePowerRequestStandby",            '?', ""   },
590 	{0XAC32C9CC, nullptr,                                     "scePowerRequestSuspend",            '?', ""   },
591 	{0X2875994B, nullptr,                                     "scePower_2875994B",                 '?', ""   },
592 	{0X0074EF9B, nullptr,                                     "scePowerGetResumeCount",            '?', ""   },
593 	{0XDFA8BAF8, &WrapI_I<scePowerUnregisterCallback>,        "scePowerUnregisterCallback",        'i', "i"  },
594 	{0XDB9D28DD, &WrapI_I<scePowerUnregisterCallback>,        "scePowerUnregitserCallback",        'i', "i"  },
595 	{0X843FBF43, &WrapU_U<scePowerSetCpuClockFrequency>,      "scePowerSetCpuClockFrequency",      'x', "x"  },
596 	{0XB8D7B3FB, &WrapU_U<scePowerSetBusClockFrequency>,      "scePowerSetBusClockFrequency",      'x', "x"  },
597 	{0XFEE03A2F, &WrapU_V<scePowerGetCpuClockFrequencyInt>,   "scePowerGetCpuClockFrequency",      'x', ""   },
598 	{0X478FE6F5, &WrapU_V<scePowerGetBusClockFrequencyInt>,   "scePowerGetBusClockFrequency",      'x', ""   },
599 	{0XFDB5BFE9, &WrapU_V<scePowerGetCpuClockFrequencyInt>,   "scePowerGetCpuClockFrequencyInt",   'x', ""   },
600 	{0XBD681969, &WrapU_V<scePowerGetBusClockFrequencyInt>,   "scePowerGetBusClockFrequencyInt",   'x', ""   },
601 	{0XB1A52C83, &WrapF_V<scePowerGetCpuClockFrequencyFloat>, "scePowerGetCpuClockFrequencyFloat", 'f', ""   },
602 	{0X9BADB3EB, &WrapF_V<scePowerGetBusClockFrequencyFloat>, "scePowerGetBusClockFrequencyFloat", 'f', ""   },
603 	{0X737486F2, &WrapU_UUU<scePowerSetClockFrequency>,       "scePowerSetClockFrequency",         'x', "xxx"},
604 	{0X34F9C463, &WrapU_V<scePowerGetPllClockFrequencyInt>,   "scePowerGetPllClockFrequencyInt",   'x', ""   },
605 	{0XEA382A27, &WrapF_V<scePowerGetPllClockFrequencyFloat>, "scePowerGetPllClockFrequencyFloat", 'f', ""   },
606 	{0XEBD177D6, &WrapU_UUU<scePowerSetClockFrequency>,       "scePower_EBD177D6",                 'x', "xxx"}, // This is also the same as SetClockFrequency
607 	{0X469989AD, &WrapU_UUU<scePowerSetClockFrequency>,       "scePower_469989ad",                 'x', "xxx"}, // This is also the same as SetClockFrequency
608 	{0X545A7F3C, nullptr,                                     "scePower_545A7F3C",                 '?', ""   }, // TODO: Supposedly the same as SetClockFrequency also?
609 	{0XA4E93389, nullptr,                                     "scePower_A4E93389",                 '?', ""   }, // TODO: Supposedly the same as SetClockFrequency also?
610 	{0XA85880D0, &WrapU_V<IsPSPNonFat>,                       "scePower_a85880d0_IsPSPNonFat",     'x', ""   },
611 	{0X3951AF53, nullptr,                                     "scePowerWaitRequestCompletion",     '?', ""   },
612 	{0X0442D852, nullptr,                                     "scePowerRequestColdReset",          '?', ""   },
613 	{0XBAFA3DF0, nullptr,                                     "scePowerGetCallbackMode",           '?', ""   },
614 	{0XA9D22232, nullptr,                                     "scePowerSetCallbackMode",           '?', ""   },
615 
616 	// These seem to be aliases.
617 	{0X23C31FFE, &WrapI_IUU<sceKernelVolatileMemLock>,        "scePowerVolatileMemLock",           'i', "ixx"},
618 	{0XFA97A599, &WrapI_IUU<sceKernelVolatileMemTryLock>,     "scePowerVolatileMemTryLock",        'i', "ixx"},
619 	{0XB3EDD801, &WrapI_I<sceKernelVolatileMemUnlock>,        "scePowerVolatileMemUnlock",         'i', "i"  },
620 };
621 
622 //890129c in tyshooter looks bogus
623 const HLEFunction sceSuspendForUser[] = {
624 	{0XEADB1BD7, &WrapI_I<sceKernelPowerLock>,                "sceKernelPowerLock",                'i', "i"  }, //(int param) set param to 0
625 	{0X3AEE7261, &WrapI_I<sceKernelPowerUnlock>,              "sceKernelPowerUnlock",              'i', "i"  }, //(int param) set param to 0
626 	{0X090CCB3F, &WrapI_I<sceKernelPowerTick>,                "sceKernelPowerTick",                'i', "i"  },
627 
628 	// There's an extra 4MB that can be allocated, which seems to be "volatile". These functions
629 	// let you grab it.
630 	{0XA14F40B2, &WrapI_IUU<sceKernelVolatileMemTryLock>,     "sceKernelVolatileMemTryLock",       'i', "ixx"},
631 	{0XA569E425, &WrapI_I<sceKernelVolatileMemUnlock>,        "sceKernelVolatileMemUnlock",        'i', "i"  },
632 	{0X3E0271D3, &WrapI_IUU<sceKernelVolatileMemLock>,        "sceKernelVolatileMemLock",          'i', "ixx"},
633 };
634 
635 
Register_scePower()636 void Register_scePower() {
637 	RegisterModule("scePower",ARRAY_SIZE(scePower),scePower);
638 }
639 
Register_sceSuspendForUser()640 void Register_sceSuspendForUser() {
641 	RegisterModule("sceSuspendForUser", ARRAY_SIZE(sceSuspendForUser), sceSuspendForUser);
642 }
643