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