2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2012-11-11 22:50:48 +01:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2012-11-01 16:19:01 +01:00
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2012-11-10 10:15:11 +01:00
# include <map>
2013-08-26 01:04:37 -07:00
# include <vector>
2013-08-21 01:10:30 -07:00
# include "Common/ChunkFile.h"
# include "Core/HLE/HLE.h"
2014-03-15 11:22:19 -07:00
# include "Core/HLE/FunctionWrappers.h"
2013-08-21 01:10:30 -07:00
# include "Core/CoreTiming.h"
2014-03-15 11:22:19 -07:00
# include "Core/MemMap.h"
2013-08-21 01:10:30 -07:00
# include "Core/Reporting.h"
2013-06-12 17:15:45 -04:00
# include "Core/Config.h"
2012-11-01 16:19:01 +01:00
2013-08-21 01:10:30 -07:00
# include "Core/HLE/scePower.h"
# include "Core/HLE/sceKernelThread.h"
2013-09-09 23:49:06 -07:00
# include "Core/HLE/sceKernelInterrupt.h"
2013-08-21 01:10:30 -07:00
2013-08-26 01:04:37 -07:00
struct VolatileWaitingThread {
SceUID threadID ;
u32 addrPtr ;
u32 sizePtr ;
} ;
2012-12-09 13:48:25 -08:00
const int PSP_POWER_ERROR_TAKEN_SLOT = 0x80000020 ;
const int PSP_POWER_ERROR_SLOTS_FULL = 0x80000022 ;
const int PSP_POWER_ERROR_EMPTY_SLOT = 0x80000025 ;
const int PSP_POWER_ERROR_INVALID_CB = 0x80000100 ;
const int PSP_POWER_ERROR_INVALID_SLOT = 0x80000102 ;
const int PSP_POWER_CB_AC_POWER = 0x00001000 ;
const int PSP_POWER_CB_BATTERY_EXIST = 0x00000080 ;
const int PSP_POWER_CB_BATTERY_FULL = 0x00000064 ;
2012-11-11 21:32:44 +00:00
const int POWER_CB_AUTO = - 1 ;
2012-12-09 13:48:25 -08:00
2014-04-03 21:38:58 +02:00
// These are the callback slots for user mode applications.
2012-11-11 21:32:44 +00:00
const int numberOfCBPowerSlots = 16 ;
2014-04-03 18:12:22 +02:00
2014-04-03 21:38:58 +02:00
// These are the callback slots for kernel mode applications.
2012-12-09 13:48:25 -08:00
const int numberOfCBPowerSlotsPrivate = 32 ;
2012-11-11 21:32:44 +00:00
2012-12-23 22:47:52 -08:00
static bool volatileMemLocked ;
static int powerCbSlots [ numberOfCBPowerSlots ] ;
2013-08-26 01:04:37 -07:00
static std : : vector < VolatileWaitingThread > volatileWaitingThreads ;
2012-11-10 10:15:11 +01:00
2013-11-28 12:35:15 -05:00
// Should this belong here, or in CoreTiming?
2016-12-30 07:01:37 +08:00
static int RealpllFreq = 222 ;
static int RealbusFreq = 111 ;
2013-03-02 14:32:31 +01:00
static int pllFreq = 222 ;
static int busFreq = 111 ;
2012-11-10 10:15:11 +01:00
void __PowerInit ( ) {
memset ( powerCbSlots , 0 , sizeof ( powerCbSlots ) ) ;
2012-12-23 22:47:52 -08:00
volatileMemLocked = false ;
2013-08-26 01:04:37 -07:00
volatileWaitingThreads . clear ( ) ;
2013-06-12 17:15:45 -04:00
2014-03-04 07:55:08 -08:00
if ( g_Config . iLockedCPUSpeed > 0 ) {
2013-06-12 17:15:45 -04:00
CoreTiming : : SetClockFrequencyMHz ( g_Config . iLockedCPUSpeed ) ;
pllFreq = g_Config . iLockedCPUSpeed ;
busFreq = g_Config . iLockedCPUSpeed / 2 ;
2014-03-04 07:55:08 -08:00
} else {
pllFreq = 222 ;
busFreq = 111 ;
2013-06-12 17:15:45 -04:00
}
2016-12-30 07:01:37 +08:00
RealpllFreq = 222 ;
RealbusFreq = 111 ;
2012-11-10 10:15:11 +01:00
}
2012-12-27 23:00:04 -08:00
void __PowerDoState ( PointerWrap & p ) {
2016-12-30 07:01:37 +08:00
auto s = p . Section ( " scePower " , 1 , 2 ) ;
2013-09-14 20:23:03 -07:00
if ( ! s )
return ;
2016-12-30 07:01:37 +08:00
if ( s > = 2 ) {
p . Do ( RealpllFreq ) ;
p . Do ( RealbusFreq ) ;
}
else {
RealpllFreq = 222 ;
RealbusFreq = 111 ;
}
if ( g_Config . iLockedCPUSpeed > 0 ) {
CoreTiming : : SetClockFrequencyMHz ( g_Config . iLockedCPUSpeed ) ;
pllFreq = g_Config . iLockedCPUSpeed ;
busFreq = g_Config . iLockedCPUSpeed / 2 ;
}
else {
pllFreq = RealpllFreq ;
busFreq = RealbusFreq ;
}
2012-12-27 23:00:04 -08:00
p . DoArray ( powerCbSlots , ARRAY_SIZE ( powerCbSlots ) ) ;
p . Do ( volatileMemLocked ) ;
2013-08-26 01:04:37 -07:00
p . Do ( volatileWaitingThreads ) ;
2012-12-27 23:00:04 -08:00
}
2014-12-08 04:40:08 -05:00
static int scePowerGetBatteryLifePercent ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 100=scePowerGetBatteryLifePercent " ) ;
2012-11-11 21:32:44 +00:00
return 100 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 22:50:48 +01:00
2014-12-08 04:40:08 -05:00
static int scePowerGetBatteryLifeTime ( ) {
2013-01-11 00:15:16 -08:00
DEBUG_LOG ( HLE , " 0=scePowerGetBatteryLifeTime() " ) ;
// 0 means we're on AC power.
return 0 ;
}
2014-12-08 04:40:08 -05:00
static int scePowerGetBatteryTemp ( ) {
2013-06-23 16:52:41 +09:00
DEBUG_LOG ( HLE , " 0=scePowerGetBatteryTemp() " ) ;
// 0 means celsius temperature of the battery
return 0 ;
}
2014-12-08 04:40:08 -05:00
static int scePowerIsPowerOnline ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 1=scePowerIsPowerOnline " ) ;
2012-11-11 21:32:44 +00:00
return 1 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 22:50:48 +01:00
2014-12-08 04:40:08 -05:00
static int scePowerIsBatteryExist ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 1=scePowerIsBatteryExist " ) ;
2012-11-11 21:32:44 +00:00
return 1 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 22:50:48 +01:00
2014-12-08 04:40:08 -05:00
static int scePowerIsBatteryCharging ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 0=scePowerIsBatteryCharging " ) ;
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 22:50:48 +01:00
2014-12-08 04:40:08 -05:00
static int scePowerGetBatteryChargingStatus ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 0=scePowerGetBatteryChargingStatus " ) ;
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 22:50:48 +01:00
2014-12-08 04:40:08 -05:00
static int scePowerIsLowBattery ( ) {
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( HLE , " 0=scePowerIsLowBattery " ) ;
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static int scePowerRegisterCallback ( int slot , int cbId ) {
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " 0=scePowerRegisterCallback(%i, %i) " , slot , cbId ) ;
if ( slot < - 1 | | slot > = numberOfCBPowerSlotsPrivate ) {
return PSP_POWER_ERROR_INVALID_SLOT ;
}
if ( slot > = numberOfCBPowerSlots ) {
2014-04-03 18:12:22 +02:00
return SCE_KERNEL_ERROR_PRIV_REQUIRED ;
2012-12-09 13:48:25 -08:00
}
// TODO: If cbId is invalid return PSP_POWER_ERROR_INVALID_CB.
if ( cbId = = 0 ) {
return PSP_POWER_ERROR_INVALID_CB ;
}
int retval = - 1 ;
2012-11-11 21:32:44 +00:00
2012-12-09 19:41:19 +07:00
if ( slot = = POWER_CB_AUTO ) { // -1 signifies auto select of bank
for ( int i = 0 ; i < numberOfCBPowerSlots ; i + + ) {
2012-12-09 13:48:25 -08:00
if ( powerCbSlots [ i ] = = 0 & & retval = = - 1 ) { // found an empty slot
2012-11-11 21:32:44 +00:00
powerCbSlots [ i ] = cbId ;
2012-12-09 13:48:25 -08:00
retval = i ;
2012-11-11 19:30:48 +01:00
}
}
2012-12-09 13:48:25 -08:00
if ( retval = = - 1 ) {
return PSP_POWER_ERROR_SLOTS_FULL ;
}
2012-12-09 19:41:19 +07:00
} else {
if ( powerCbSlots [ slot ] = = 0 ) {
2012-11-11 21:32:44 +00:00
powerCbSlots [ slot ] = cbId ;
2012-12-09 13:48:25 -08:00
retval = 0 ;
2012-12-09 19:41:19 +07:00
} else {
2012-12-09 13:48:25 -08:00
return PSP_POWER_ERROR_TAKEN_SLOT ;
2012-11-11 19:30:48 +01:00
}
}
2012-12-09 13:48:25 -08:00
if ( retval > = 0 ) {
int arg = PSP_POWER_CB_AC_POWER | PSP_POWER_CB_BATTERY_EXIST | PSP_POWER_CB_BATTERY_FULL ;
2013-09-02 01:25:41 -07:00
__KernelNotifyCallback ( cbId , arg ) ;
2012-11-11 21:32:44 +00:00
}
2012-12-09 13:48:25 -08:00
return retval ;
2012-11-10 10:15:11 +01:00
}
2014-12-08 04:40:08 -05:00
static int scePowerUnregisterCallback ( int slotId ) {
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " 0=scePowerUnregisterCallback(%i) " , slotId ) ;
if ( slotId < 0 | | slotId > = numberOfCBPowerSlotsPrivate ) {
return PSP_POWER_ERROR_INVALID_SLOT ;
}
if ( slotId > = numberOfCBPowerSlots ) {
2014-04-03 18:42:10 +02:00
return SCE_KERNEL_ERROR_PRIV_REQUIRED ;
2012-11-11 22:50:48 +01:00
}
2012-11-11 21:32:44 +00:00
2012-12-09 19:41:19 +07:00
if ( powerCbSlots [ slotId ] ! = 0 ) {
2012-11-11 19:30:48 +01:00
int cbId = powerCbSlots [ slotId ] ;
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " 0=scePowerUnregisterCallback(%i) (cbid = %i) " , slotId , cbId ) ;
2012-11-11 19:30:48 +01:00
powerCbSlots [ slotId ] = 0 ;
2012-12-09 19:41:19 +07:00
} else {
2012-12-09 13:48:25 -08:00
return PSP_POWER_ERROR_EMPTY_SLOT ;
2012-11-11 22:50:48 +01:00
}
2012-11-11 21:32:44 +00:00
2012-11-11 22:50:48 +01:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-10 10:15:11 +01:00
2014-12-08 04:40:08 -05:00
static int sceKernelPowerLock ( int lockType ) {
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " 0=sceKernelPowerLock(%i) " , lockType ) ;
if ( lockType = = 0 ) {
return 0 ;
} else {
2013-03-31 23:42:56 -07:00
return SCE_KERNEL_ERROR_INVALID_MODE ;
2012-12-09 13:48:25 -08:00
}
2012-11-01 16:19:01 +01:00
}
2012-12-09 19:41:19 +07:00
2014-12-08 04:40:08 -05:00
static int sceKernelPowerUnlock ( int lockType ) {
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " 0=sceKernelPowerUnlock(%i) " , lockType ) ;
if ( lockType = = 0 ) {
return 0 ;
} else {
2013-03-31 23:42:56 -07:00
return SCE_KERNEL_ERROR_INVALID_MODE ;
2012-12-09 13:48:25 -08:00
}
2012-11-01 16:19:01 +01:00
}
2012-12-09 19:41:19 +07:00
2014-12-08 04:40:08 -05:00
static int sceKernelPowerTick ( int flag ) {
2012-12-09 13:48:25 -08:00
DEBUG_LOG ( HLE , " UNIMPL 0=sceKernelPowerTick(%i) " , flag ) ;
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static int __KernelVolatileMemLock ( int type , u32 paddr , u32 psize ) {
2013-08-26 01:04:37 -07:00
if ( type ! = 0 ) {
return SCE_KERNEL_ERROR_INVALID_MODE ;
}
if ( volatileMemLocked ) {
2014-04-27 20:31:40 +08:00
return SCE_KERNEL_ERROR_POWER_VMEM_IN_USE ;
2012-11-11 21:32:44 +00:00
}
2012-11-01 16:19:01 +01:00
2012-11-11 21:32:44 +00:00
// Volatile RAM is always at 0x08400000 and is of size 0x00400000.
// It's always available in the emu.
2012-11-19 09:25:50 +01:00
// TODO: Should really reserve this properly!
2014-03-24 00:49:27 -07:00
if ( Memory : : IsValidAddress ( paddr ) ) {
Memory : : Write_U32 ( 0x08400000 , paddr ) ;
}
if ( Memory : : IsValidAddress ( psize ) ) {
Memory : : Write_U32 ( 0x00400000 , psize ) ;
}
2013-08-26 01:04:37 -07:00
volatileMemLocked = true ;
2012-11-01 16:19:01 +01:00
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static int sceKernelVolatileMemTryLock ( int type , u32 paddr , u32 psize ) {
2013-08-26 06:01:23 -07:00
u32 error = __KernelVolatileMemLock ( type , paddr , psize ) ;
2013-08-26 01:04:37 -07:00
switch ( error ) {
case 0 :
2014-03-24 00:49:27 -07:00
// HACK: This fixes Crash Tag Team Racing.
// Should only wait 1200 cycles though according to Unknown's testing,
// and with that it's still broken. So it's not this, unfortunately.
// Leaving it in for the 0.9.8 release anyway.
hleEatCycles ( 500000 ) ;
2013-11-08 18:52:07 +01:00
DEBUG_LOG ( HLE , " sceKernelVolatileMemTryLock(%i, %08x, %08x) - success " , type , paddr , psize ) ;
2013-08-26 01:04:37 -07:00
break ;
2014-04-27 20:31:40 +08:00
case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE :
2013-08-26 01:04:37 -07:00
ERROR_LOG ( HLE , " sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked! " , type , paddr , psize ) ;
break ;
default :
ERROR_LOG_REPORT ( HLE , " %08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error " , type , paddr , psize , error ) ;
break ;
}
return error ;
}
2014-12-08 04:40:08 -05:00
static int sceKernelVolatileMemUnlock ( int type ) {
2013-08-26 01:04:37 -07:00
if ( type ! = 0 ) {
ERROR_LOG_REPORT ( HLE , " sceKernelVolatileMemUnlock(%i) - invalid mode " , type ) ;
return SCE_KERNEL_ERROR_INVALID_MODE ;
}
2012-12-09 19:41:19 +07:00
if ( volatileMemLocked ) {
volatileMemLocked = false ;
2013-08-26 01:04:37 -07:00
// Wake someone, always fifo.
bool wokeThreads = false ;
u32 error ;
while ( ! volatileWaitingThreads . empty ( ) & & ! volatileMemLocked ) {
VolatileWaitingThread waitInfo = volatileWaitingThreads . front ( ) ;
volatileWaitingThreads . erase ( volatileWaitingThreads . begin ( ) ) ;
int waitID = __KernelGetWaitID ( waitInfo . threadID , WAITTYPE_VMEM , error ) ;
// If they were force-released, just skip.
if ( waitID = = 1 & & __KernelVolatileMemLock ( 0 , waitInfo . addrPtr , waitInfo . sizePtr ) = = 0 ) {
__KernelResumeThreadFromWait ( waitInfo . threadID , 0 ) ;
wokeThreads = true ;
}
}
if ( wokeThreads ) {
INFO_LOG ( HLE , " sceKernelVolatileMemUnlock(%i) handed over to another thread " , type ) ;
hleReSchedule ( " volatile mem unlocked " ) ;
} else {
2013-11-08 18:52:07 +01:00
DEBUG_LOG ( HLE , " sceKernelVolatileMemUnlock(%i) " , type ) ;
2013-08-26 01:04:37 -07:00
}
2012-12-09 19:41:19 +07:00
} else {
2013-08-21 01:10:30 -07:00
ERROR_LOG_REPORT ( HLE , " sceKernelVolatileMemUnlock(%i) FAILED - not locked " , type ) ;
2013-09-09 23:49:06 -07:00
// I guess it must use a sema.
return SCE_KERNEL_ERROR_SEMA_OVF ;
2012-12-09 19:41:19 +07:00
}
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static int sceKernelVolatileMemLock ( int type , u32 paddr , u32 psize ) {
2013-09-09 23:49:06 -07:00
u32 error = 0 ;
// If dispatch is disabled or in an interrupt, don't check, just return an error.
// But still write the addr and size (some games require this to work, and it's testably true.)
if ( ! __KernelIsDispatchEnabled ( ) ) {
error = SCE_KERNEL_ERROR_CAN_NOT_WAIT ;
} else if ( __IsInInterrupt ( ) ) {
error = SCE_KERNEL_ERROR_ILLEGAL_CONTEXT ;
} else {
error = __KernelVolatileMemLock ( type , paddr , psize ) ;
}
2013-08-26 01:04:37 -07:00
switch ( error ) {
case 0 :
2014-03-24 00:49:27 -07:00
// HACK: This fixes Crash Tag Team Racing.
// Should only wait 1200 cycles though according to Unknown's testing,
// and with that it's still broken. So it's not this, unfortunately.
// Leaving it in for the 0.9.8 release anyway.
hleEatCycles ( 500000 ) ;
2013-11-08 18:52:07 +01:00
DEBUG_LOG ( HLE , " sceKernelVolatileMemLock(%i, %08x, %08x) - success " , type , paddr , psize ) ;
2013-08-26 01:04:37 -07:00
break ;
2014-04-27 20:31:40 +08:00
case SCE_KERNEL_ERROR_POWER_VMEM_IN_USE :
2013-08-26 01:04:37 -07:00
{
WARN_LOG ( HLE , " sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting " , type , paddr , psize ) ;
const VolatileWaitingThread waitInfo = { __KernelGetCurThread ( ) , paddr , psize } ;
volatileWaitingThreads . push_back ( waitInfo ) ;
__KernelWaitCurThread ( WAITTYPE_VMEM , 1 , 0 , 0 , false , " volatile mem waited " ) ;
}
break ;
2013-09-09 23:49:06 -07:00
case SCE_KERNEL_ERROR_CAN_NOT_WAIT :
{
WARN_LOG ( HLE , " sceKernelVolatileMemLock(%i, %08x, %08x): dispatch disabled " , type , paddr , psize ) ;
Memory : : Write_U32 ( 0x08400000 , paddr ) ;
Memory : : Write_U32 ( 0x00400000 , psize ) ;
}
break ;
case SCE_KERNEL_ERROR_ILLEGAL_CONTEXT :
{
2013-09-10 01:21:20 -07:00
WARN_LOG ( HLE , " sceKernelVolatileMemLock(%i, %08x, %08x): in interrupt " , type , paddr , psize ) ;
2013-09-09 23:49:06 -07:00
Memory : : Write_U32 ( 0x08400000 , paddr ) ;
Memory : : Write_U32 ( 0x00400000 , psize ) ;
}
break ;
2013-08-26 01:04:37 -07:00
default :
ERROR_LOG_REPORT ( HLE , " %08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error " , type , paddr , psize , error ) ;
break ;
}
return error ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static u32 scePowerSetClockFrequency ( u32 pllfreq , u32 cpufreq , u32 busfreq ) {
2016-12-30 07:01:37 +08:00
if ( cpufreq = = 0 | | cpufreq > 333 ) {
WARN_LOG ( HLE , " scePowerSetClockFrequency(%i,%i,%i): invalid frequency " , pllfreq , cpufreq , busfreq ) ;
return SCE_KERNEL_ERROR_INVALID_VALUE ;
}
// TODO: More restrictions.
2013-11-08 18:52:07 +01:00
if ( g_Config . iLockedCPUSpeed > 0 ) {
2016-12-30 07:01:37 +08:00
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 ) ;
2013-06-12 17:15:45 -04:00
}
else {
2016-12-30 07:01:37 +08:00
INFO_LOG ( HLE , " scePowerSetClockFrequency(%i,%i,%i) " , pllfreq , cpufreq , busfreq ) ;
}
if ( RealpllFreq ! = pllfreq | | RealbusFreq ! = busfreq ) {
RealpllFreq = pllfreq ;
RealbusFreq = busfreq ;
if ( g_Config . iLockedCPUSpeed < = 0 ) {
pllFreq = pllfreq ;
busFreq = busfreq ;
CoreTiming : : SetClockFrequencyMHz ( cpufreq ) ;
2013-03-05 08:21:21 -08:00
}
2016-12-30 07:01:37 +08:00
return hleDelayResult ( 0 , " scepower set clockFrequency " , 150000 ) ;
2013-06-12 17:15:45 -04:00
}
2016-12-30 07:01:37 +08:00
if ( g_Config . iLockedCPUSpeed < = 0 )
CoreTiming : : SetClockFrequencyMHz ( cpufreq ) ;
return 0 ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static u32 scePowerSetCpuClockFrequency ( u32 cpufreq ) {
2013-06-12 17:15:45 -04:00
if ( g_Config . iLockedCPUSpeed > 0 ) {
DEBUG_LOG ( HLE , " scePowerSetCpuClockFrequency(%i): locked by user config at %i " , cpufreq , g_Config . iLockedCPUSpeed ) ;
}
else {
2013-03-05 08:21:21 -08:00
if ( cpufreq = = 0 | | cpufreq > 333 ) {
WARN_LOG ( HLE , " scePowerSetCpuClockFrequency(%i): invalid frequency " , cpufreq ) ;
return SCE_KERNEL_ERROR_INVALID_VALUE ;
}
2013-06-12 17:15:45 -04:00
CoreTiming : : SetClockFrequencyMHz ( cpufreq ) ;
2016-09-06 19:28:23 +08:00
INFO_LOG ( HLE , " scePowerSetCpuClockFrequency(%i) " , cpufreq ) ;
2013-06-12 17:15:45 -04:00
}
2012-12-26 21:08:41 +01:00
return 0 ;
}
2014-12-08 04:40:08 -05:00
static u32 scePowerSetBusClockFrequency ( u32 busfreq ) {
2013-06-12 17:15:45 -04:00
if ( g_Config . iLockedCPUSpeed > 0 ) {
DEBUG_LOG ( HLE , " scePowerSetBusClockFrequency(%i): locked by user config at %i " , busfreq , busFreq ) ;
}
else {
2013-03-05 08:21:21 -08:00
if ( busfreq = = 0 | | busfreq > 111 ) {
WARN_LOG ( HLE , " scePowerSetBusClockFrequency(%i): invalid frequency " , busfreq ) ;
return SCE_KERNEL_ERROR_INVALID_VALUE ;
}
// TODO: It seems related to other frequencies, though.
2013-06-12 17:15:45 -04:00
busFreq = busfreq ;
2016-09-06 19:28:23 +08:00
INFO_LOG ( HLE , " scePowerSetBusClockFrequency(%i) " , busfreq ) ;
2013-06-12 17:15:45 -04:00
}
2012-12-26 21:08:41 +01:00
return 0 ;
}
2014-12-08 04:40:08 -05:00
static u32 scePowerGetCpuClockFrequencyInt ( ) {
2013-03-19 06:09:37 +08:00
int cpuFreq = CoreTiming : : GetClockFrequencyMHz ( ) ;
2016-09-06 19:28:23 +08:00
INFO_LOG ( HLE , " %i=scePowerGetCpuClockFrequencyInt() " , cpuFreq ) ;
2013-03-19 06:09:37 +08:00
return cpuFreq ;
2012-11-12 00:04:57 +01:00
}
2014-12-08 04:40:08 -05:00
static u32 scePowerGetPllClockFrequencyInt ( ) {
2013-03-02 14:32:31 +01:00
INFO_LOG ( HLE , " %i=scePowerGetPllClockFrequencyInt() " , pllFreq ) ;
return pllFreq ;
2012-11-12 00:04:57 +01:00
}
2014-12-08 04:40:08 -05:00
static u32 scePowerGetBusClockFrequencyInt ( ) {
2013-03-19 06:09:37 +08:00
INFO_LOG ( HLE , " %i=scePowerGetBusClockFrequencyInt() " , busFreq ) ;
return busFreq ;
}
2014-12-08 04:40:08 -05:00
static float scePowerGetCpuClockFrequencyFloat ( ) {
2013-03-19 06:09:37 +08:00
int cpuFreq = CoreTiming : : GetClockFrequencyMHz ( ) ;
INFO_LOG ( HLE , " %f=scePowerGetCpuClockFrequencyFloat() " , ( float ) cpuFreq ) ;
return ( float ) cpuFreq ;
}
2014-12-08 04:40:08 -05:00
static float scePowerGetPllClockFrequencyFloat ( ) {
2013-03-04 23:39:59 +01:00
INFO_LOG ( HLE , " %f=scePowerGetPllClockFrequencyFloat() " , ( float ) pllFreq ) ;
return ( float ) pllFreq ;
}
2014-12-08 04:40:08 -05:00
static float scePowerGetBusClockFrequencyFloat ( ) {
2013-03-19 06:09:37 +08:00
INFO_LOG ( HLE , " %f=scePowerGetBusClockFrequencyFloat() " , ( float ) busFreq ) ;
return ( float ) busFreq ;
2012-11-01 16:19:01 +01:00
}
2014-12-08 04:40:08 -05:00
static int scePowerTick ( ) {
2013-06-11 11:48:45 +02:00
DEBUG_LOG ( HLE , " scePowerTick() " ) ;
// Don't think we need to do anything.
return 0 ;
}
2013-03-19 06:09:37 +08:00
2014-12-08 04:40:08 -05:00
static u32 IsPSPNonFat ( ) {
2013-11-28 12:35:15 -05:00
DEBUG_LOG ( HLE , " %d=scePower_a85880d0_IsPSPNonFat() " , g_Config . iPSPModel ) ;
return g_Config . iPSPModel ;
2013-02-02 00:22:01 +01:00
}
2012-12-09 19:41:19 +07:00
static const HLEFunction scePower [ ] = {
2015-03-22 16:57:56 -07:00
{ 0X04B7766E , & WrapI_II < scePowerRegisterCallback > , " scePowerRegisterCallback " , ' i ' , " ii " } ,
{ 0X2B51FE2F , nullptr , " scePower_2B51FE2F " , ' ? ' , " " } ,
{ 0X442BFBAC , nullptr , " scePowerGetBacklightMaximum " , ' ? ' , " " } ,
{ 0XEFD3C963 , & WrapI_V < scePowerTick > , " scePowerTick " , ' i ' , " " } ,
{ 0XEDC13FE5 , nullptr , " scePowerGetIdleTimer " , ' ? ' , " " } ,
{ 0X7F30B3B1 , nullptr , " scePowerIdleTimerEnable " , ' ? ' , " " } ,
{ 0X972CE941 , nullptr , " scePowerIdleTimerDisable " , ' ? ' , " " } ,
{ 0X27F3292C , nullptr , " scePowerBatteryUpdateInfo " , ' ? ' , " " } ,
{ 0XE8E4E204 , nullptr , " scePower_E8E4E204 " , ' ? ' , " " } ,
{ 0XB999184C , nullptr , " scePowerGetLowBatteryCapacity " , ' ? ' , " " } ,
{ 0X87440F5E , & WrapI_V < scePowerIsPowerOnline > , " scePowerIsPowerOnline " , ' i ' , " " } ,
{ 0X0AFD0D8B , & WrapI_V < scePowerIsBatteryExist > , " scePowerIsBatteryExist " , ' i ' , " " } ,
{ 0X1E490401 , & WrapI_V < scePowerIsBatteryCharging > , " scePowerIsBatteryCharging " , ' i ' , " " } ,
{ 0XB4432BC8 , & WrapI_V < scePowerGetBatteryChargingStatus > , " scePowerGetBatteryChargingStatus " , ' i ' , " " } ,
{ 0XD3075926 , & WrapI_V < scePowerIsLowBattery > , " scePowerIsLowBattery " , ' i ' , " " } ,
{ 0X78A1A796 , nullptr , " scePowerIsSuspendRequired " , ' ? ' , " " } ,
{ 0X94F5A53F , nullptr , " scePowerGetBatteryRemainCapacity " , ' ? ' , " " } ,
{ 0XFD18A0FF , nullptr , " scePowerGetBatteryFullCapacity " , ' ? ' , " " } ,
{ 0X2085D15D , & WrapI_V < scePowerGetBatteryLifePercent > , " scePowerGetBatteryLifePercent " , ' i ' , " " } ,
{ 0X8EFB3FA2 , & WrapI_V < scePowerGetBatteryLifeTime > , " scePowerGetBatteryLifeTime " , ' i ' , " " } ,
{ 0X28E12023 , & WrapI_V < scePowerGetBatteryTemp > , " scePowerGetBatteryTemp " , ' i ' , " " } ,
{ 0X862AE1A6 , nullptr , " scePowerGetBatteryElec " , ' ? ' , " " } ,
{ 0X483CE86B , nullptr , " scePowerGetBatteryVolt " , ' ? ' , " " } ,
{ 0XCB49F5CE , nullptr , " scePowerGetBatteryChargeCycle " , ' ? ' , " " } ,
{ 0X23436A4A , nullptr , " scePowerGetInnerTemp " , ' ? ' , " " } ,
{ 0X0CD21B1F , nullptr , " scePowerSetPowerSwMode " , ' ? ' , " " } ,
{ 0X165CE085 , nullptr , " scePowerGetPowerSwMode " , ' ? ' , " " } ,
{ 0XD6D016EF , nullptr , " scePowerLock " , ' ? ' , " " } ,
{ 0XCA3D34C1 , nullptr , " scePowerUnlock " , ' ? ' , " " } ,
{ 0XDB62C9CF , nullptr , " scePowerCancelRequest " , ' ? ' , " " } ,
{ 0X7FA406DD , nullptr , " scePowerIsRequest " , ' ? ' , " " } ,
{ 0X2B7C7CF4 , nullptr , " scePowerRequestStandby " , ' ? ' , " " } ,
{ 0XAC32C9CC , nullptr , " scePowerRequestSuspend " , ' ? ' , " " } ,
{ 0X2875994B , nullptr , " scePower_2875994B " , ' ? ' , " " } ,
{ 0X0074EF9B , nullptr , " scePowerGetResumeCount " , ' ? ' , " " } ,
{ 0XDFA8BAF8 , & WrapI_I < scePowerUnregisterCallback > , " scePowerUnregisterCallback " , ' i ' , " i " } ,
{ 0XDB9D28DD , & WrapI_I < scePowerUnregisterCallback > , " scePowerUnregitserCallback " , ' i ' , " i " } ,
{ 0X843FBF43 , & WrapU_U < scePowerSetCpuClockFrequency > , " scePowerSetCpuClockFrequency " , ' x ' , " x " } ,
{ 0XB8D7B3FB , & WrapU_U < scePowerSetBusClockFrequency > , " scePowerSetBusClockFrequency " , ' x ' , " x " } ,
{ 0XFEE03A2F , & WrapU_V < scePowerGetCpuClockFrequencyInt > , " scePowerGetCpuClockFrequency " , ' x ' , " " } ,
{ 0X478FE6F5 , & WrapU_V < scePowerGetBusClockFrequencyInt > , " scePowerGetBusClockFrequency " , ' x ' , " " } ,
{ 0XFDB5BFE9 , & WrapU_V < scePowerGetCpuClockFrequencyInt > , " scePowerGetCpuClockFrequencyInt " , ' x ' , " " } ,
{ 0XBD681969 , & WrapU_V < scePowerGetBusClockFrequencyInt > , " scePowerGetBusClockFrequencyInt " , ' x ' , " " } ,
{ 0XB1A52C83 , & WrapF_V < scePowerGetCpuClockFrequencyFloat > , " scePowerGetCpuClockFrequencyFloat " , ' f ' , " " } ,
{ 0X9BADB3EB , & WrapF_V < scePowerGetBusClockFrequencyFloat > , " scePowerGetBusClockFrequencyFloat " , ' f ' , " " } ,
{ 0X737486F2 , & WrapU_UUU < scePowerSetClockFrequency > , " scePowerSetClockFrequency " , ' x ' , " xxx " } ,
{ 0X34F9C463 , & WrapU_V < scePowerGetPllClockFrequencyInt > , " scePowerGetPllClockFrequencyInt " , ' x ' , " " } ,
{ 0XEA382A27 , & WrapF_V < scePowerGetPllClockFrequencyFloat > , " scePowerGetPllClockFrequencyFloat " , ' f ' , " " } ,
{ 0XEBD177D6 , & WrapU_UUU < scePowerSetClockFrequency > , " scePower_EBD177D6 " , ' x ' , " xxx " } , // This is also the same as SetClockFrequency
{ 0X469989AD , & WrapU_UUU < scePowerSetClockFrequency > , " scePower_469989ad " , ' x ' , " xxx " } , // This is also the same as SetClockFrequency
{ 0X545A7F3C , nullptr , " scePower_545A7F3C " , ' ? ' , " " } , // TODO: Supposedly the same as SetClockFrequency also?
{ 0XA4E93389 , nullptr , " scePower_A4E93389 " , ' ? ' , " " } , // TODO: Supposedly the same as SetClockFrequency also?
{ 0XA85880D0 , & WrapU_V < IsPSPNonFat > , " scePower_a85880d0_IsPSPNonFat " , ' x ' , " " } ,
{ 0X3951AF53 , nullptr , " scePowerWaitRequestCompletion " , ' ? ' , " " } ,
{ 0X0442D852 , nullptr , " scePowerRequestColdReset " , ' ? ' , " " } ,
{ 0XBAFA3DF0 , nullptr , " scePowerGetCallbackMode " , ' ? ' , " " } ,
{ 0XA9D22232 , nullptr , " scePowerSetCallbackMode " , ' ? ' , " " } ,
2013-08-26 01:04:37 -07:00
// These seem to be aliases.
2015-03-22 16:57:56 -07:00
{ 0X23C31FFE , & WrapI_IUU < sceKernelVolatileMemLock > , " scePowerVolatileMemLock " , ' i ' , " ixx " } ,
{ 0XFA97A599 , & WrapI_IUU < sceKernelVolatileMemTryLock > , " scePowerVolatileMemTryLock " , ' i ' , " ixx " } ,
{ 0XB3EDD801 , & WrapI_I < sceKernelVolatileMemUnlock > , " scePowerVolatileMemUnlock " , ' i ' , " i " } ,
2012-11-01 16:19:01 +01:00
} ;
//890129c in tyshooter looks bogus
2012-12-09 19:41:19 +07:00
const HLEFunction sceSuspendForUser [ ] = {
2015-03-22 16:57:56 -07:00
{ 0XEADB1BD7 , & WrapI_I < sceKernelPowerLock > , " sceKernelPowerLock " , ' i ' , " i " } , //(int param) set param to 0
{ 0X3AEE7261 , & WrapI_I < sceKernelPowerUnlock > , " sceKernelPowerUnlock " , ' i ' , " i " } , //(int param) set param to 0
{ 0X090CCB3F , & WrapI_I < sceKernelPowerTick > , " sceKernelPowerTick " , ' i ' , " i " } ,
2012-11-11 21:32:44 +00:00
// There's an extra 4MB that can be allocated, which seems to be "volatile". These functions
// let you grab it.
2015-03-22 16:57:56 -07:00
{ 0XA14F40B2 , & WrapI_IUU < sceKernelVolatileMemTryLock > , " sceKernelVolatileMemTryLock " , ' i ' , " ixx " } ,
{ 0XA569E425 , & WrapI_I < sceKernelVolatileMemUnlock > , " sceKernelVolatileMemUnlock " , ' i ' , " i " } ,
{ 0X3E0271D3 , & WrapI_IUU < sceKernelVolatileMemLock > , " sceKernelVolatileMemLock " , ' i ' , " ixx " } ,
2012-11-01 16:19:01 +01:00
} ;
void Register_scePower ( ) {
2012-11-11 21:32:44 +00:00
RegisterModule ( " scePower " , ARRAY_SIZE ( scePower ) , scePower ) ;
2012-11-01 16:19:01 +01:00
}
void Register_sceSuspendForUser ( ) {
2012-11-11 21:32:44 +00:00
RegisterModule ( " sceSuspendForUser " , ARRAY_SIZE ( sceSuspendForUser ) , sceSuspendForUser ) ;
2012-11-01 16:19:01 +01:00
}