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>
2012-11-01 16:19:01 +01:00
# include "HLE.h"
# include "../MIPS/MIPS.h"
# include "../CoreTiming.h"
# include "scePower.h"
2012-11-10 10:15:11 +01:00
# include "sceKernelThread.h"
2012-11-01 16:19:01 +01:00
static bool volatileMemLocked ;
2012-11-11 21:32:44 +00:00
const int POWER_CB_AUTO = - 1 ;
const int numberOfCBPowerSlots = 16 ;
static int powerCbSlots [ numberOfCBPowerSlots ] ;
2012-11-10 10:15:11 +01:00
void __PowerInit ( ) {
memset ( powerCbSlots , 0 , sizeof ( powerCbSlots ) ) ;
}
2012-11-11 21:32:44 +00:00
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
2012-11-11 21:32:44 +00:00
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
2012-11-11 21:32:44 +00:00
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
2012-11-11 21:32:44 +00:00
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
2012-11-11 21:32:44 +00:00
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
2012-11-11 21:32:44 +00:00
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
}
2012-11-11 21:32:44 +00:00
int scePowerRegisterCallback ( int slot , int cbId )
2012-11-01 16:19:01 +01:00
{
2012-11-10 10:15:11 +01:00
DEBUG_LOG ( HLE , " 0=scePowerRegisterCallback(%i, %i) " , slot , cbId ) ;
2012-11-11 21:32:44 +00:00
int foundSlot = - 1 ;
if ( slot = = POWER_CB_AUTO ) // -1 signifies auto select of bank
{
for ( int i = 0 ; i < numberOfCBPowerSlots ; i + + )
{
2012-11-11 22:50:48 +01:00
if ( ( powerCbSlots [ i ] = = 0 ) & & ( foundSlot = = POWER_CB_AUTO ) ) // found an empty slot
2012-11-11 21:32:44 +00:00
{
powerCbSlots [ i ] = cbId ;
foundSlot = i ;
2012-11-11 19:30:48 +01:00
}
}
2012-11-11 21:32:44 +00:00
}
else
{
if ( powerCbSlots [ slot ] = = 0 )
{
powerCbSlots [ slot ] = cbId ;
2012-11-11 22:50:48 +01:00
foundSlot = 0 ;
2012-11-11 21:32:44 +00:00
}
else
{
// slot already in use!
foundSlot = POWER_CB_AUTO ;
2012-11-11 19:30:48 +01:00
}
}
2012-11-11 21:32:44 +00:00
if ( foundSlot > = 0 )
{
__KernelRegisterCallback ( THREAD_CALLBACK_POWER , cbId ) ;
2012-11-10 10:15:11 +01:00
2012-11-11 21:32:44 +00:00
// Immediately notify
RETURN ( 0 ) ;
2012-11-10 10:15:11 +01:00
2012-11-11 22:50:48 +01:00
__KernelNotifyCallbackType ( THREAD_CALLBACK_POWER , cbId , 0x185 ) ; // TODO: I have no idea what the 0x185 is from the flags, but its needed for the test to pass. Need another example of it being called
2012-11-11 21:32:44 +00:00
}
return foundSlot ;
2012-11-10 10:15:11 +01:00
}
2012-11-11 21:32:44 +00:00
int scePowerUnregisterCallback ( int slotId )
{
2012-11-11 22:50:48 +01:00
if ( slotId < 0 | | slotId > = numberOfCBPowerSlots )
{
return - 1 ;
}
2012-11-11 21:32:44 +00:00
2012-11-11 22:50:48 +01:00
if ( powerCbSlots [ slotId ] ! = 0 )
{
2012-11-11 19:30:48 +01:00
int cbId = powerCbSlots [ slotId ] ;
DEBUG_LOG ( HLE , " 0=scePowerUnregisterCallback(%i) (cbid = %i) " , slotId , cbId ) ;
__KernelUnregisterCallback ( THREAD_CALLBACK_POWER , cbId ) ;
powerCbSlots [ slotId ] = 0 ;
}
2012-11-11 22:50:48 +01:00
else
{
return 0x80000025 ; // TODO: docs say a value less than 0, test checks for this specifically. why??
}
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
2012-11-11 21:32:44 +00:00
int sceKernelPowerLock ( int lockType )
2012-11-01 16:19:01 +01:00
{
2012-11-11 21:32:44 +00:00
DEBUG_LOG ( HLE , " UNIMPL 0=sceKernelPowerLock(%i) " , lockType ) ;
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 21:32:44 +00:00
int sceKernelPowerUnlock ( int lockType )
2012-11-01 16:19:01 +01:00
{
2012-11-11 21:32:44 +00:00
DEBUG_LOG ( HLE , " UNIMPL 0=sceKernelPowerUnlock(%i) " ) ;
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 21:32:44 +00:00
int sceKernelPowerTick ( int flag )
2012-11-01 16:19:01 +01:00
{
DEBUG_LOG ( HLE , " UNIMPL 0=sceKernelPowerTick() " ) ;
2012-11-11 21:32:44 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
# define ERROR_POWER_VMEM_IN_USE 0x802b0200
2012-11-11 21:32:44 +00:00
int sceKernelVolatileMemTryLock ( int type , int paddr , int psize )
2012-11-01 16:19:01 +01:00
{
2012-11-11 21:32:44 +00:00
if ( ! volatileMemLocked )
{
INFO_LOG ( HLE , " sceKernelVolatileMemTryLock(%i, %08x, %i) - success " , type , paddr , psize ) ;
volatileMemLocked = true ;
}
else
{
ERROR_LOG ( HLE , " sceKernelVolatileMemTryLock - already locked! " ) ;
//RETURN(ERROR_POWER_VMEM_IN_USE); // does this line still need to be here??
return ERROR_POWER_VMEM_IN_USE ;
}
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.
Memory : : Write_U32 ( 0x08400000 , paddr ) ;
Memory : : Write_U32 ( 0x00400000 , psize ) ;
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
}
2012-11-11 21:32:44 +00:00
int sceKernelVolatileMemUnlock ( int type )
2012-11-01 16:19:01 +01:00
{
2012-11-11 21:32:44 +00:00
INFO_LOG ( HLE , " sceKernelVolatileMemUnlock() " ) ;
// TODO: sanity check
volatileMemLocked = false ;
return 0 ;
2012-11-01 16:19:01 +01:00
}
2012-11-11 21:32:44 +00:00
int sceKernelVolatileMemLock ( int type , int paddr , int psize )
2012-11-01 16:19:01 +01:00
{
2012-11-11 21:32:44 +00:00
return sceKernelVolatileMemTryLock ( type , paddr , psize ) ;
2012-11-01 16:19:01 +01:00
}
void scePowerSetClockFrequency ( u32 cpufreq , u32 busfreq , u32 gpufreq )
{
2012-11-11 21:32:44 +00:00
CoreTiming : : SetClockFrequencyMHz ( cpufreq ) ;
2012-11-01 16:19:01 +01:00
2012-11-11 21:32:44 +00:00
INFO_LOG ( HLE , " scePowerSetClockFrequency(%i,%i,%i) " , cpufreq , busfreq , gpufreq ) ;
2012-11-01 16:19:01 +01:00
}
void scePowerGetCpuClockFrequencyInt ( ) {
2012-11-12 00:04:57 +01:00
int freq = CoreTiming : : GetClockFrequencyMHz ( ) ;
INFO_LOG ( HLE , " %i=scePowerGetCpuClockFrequencyInt() " , freq ) ;
RETURN ( freq ) ;
}
void scePowerGetPllClockFrequencyInt ( ) {
int freq = CoreTiming : : GetClockFrequencyMHz ( ) / 2 ;
INFO_LOG ( HLE , " %i=scePowerGetPllClockFrequencyInt() " , freq ) ;
RETURN ( freq ) ;
}
void scePowerGetBusClockFrequencyInt ( ) {
int freq = CoreTiming : : GetClockFrequencyMHz ( ) / 2 ;
INFO_LOG ( HLE , " %i=scePowerGetBusClockFrequencyInt() " , freq ) ;
RETURN ( freq ) ;
2012-11-01 16:19:01 +01:00
}
static const HLEFunction scePower [ ] =
{
2012-11-11 21:32:44 +00:00
{ 0x04B7766E , & WrapI_II < scePowerRegisterCallback > , " scePowerRegisterCallback " } ,
{ 0x2B51FE2F , 0 , " scePower_2B51FE2F " } ,
{ 0x442BFBAC , 0 , " scePowerGetBacklightMaximum " } ,
{ 0xEFD3C963 , 0 , " scePowerTick " } ,
{ 0xEDC13FE5 , 0 , " scePowerGetIdleTimer " } ,
{ 0x7F30B3B1 , 0 , " scePowerIdleTimerEnable " } ,
{ 0x972CE941 , 0 , " scePowerIdleTimerDisable " } ,
{ 0x27F3292C , 0 , " scePowerBatteryUpdateInfo " } ,
{ 0xE8E4E204 , 0 , " scePower_E8E4E204 " } ,
{ 0xB999184C , 0 , " scePowerGetLowBatteryCapacity " } ,
{ 0x87440F5E , & WrapI_V < scePowerIsPowerOnline > , " scePowerIsPowerOnline " } ,
{ 0x0AFD0D8B , & WrapI_V < scePowerIsBatteryExist > , " scePowerIsBatteryExist " } ,
{ 0x1E490401 , & WrapI_V < scePowerIsBatteryCharging > , " scePowerIsBatteryCharging " } ,
{ 0xB4432BC8 , & WrapI_V < scePowerGetBatteryChargingStatus > , " scePowerGetBatteryChargingStatus " } ,
{ 0xD3075926 , & WrapI_V < scePowerIsLowBattery > , " scePowerIsLowBattery " } ,
{ 0x78A1A796 , 0 , " scePowerIsSuspendRequired " } ,
{ 0x94F5A53F , 0 , " scePowerGetBatteryRemainCapacity " } ,
{ 0xFD18A0FF , 0 , " scePowerGetBatteryFullCapacity " } ,
{ 0x2085D15D , & WrapI_V < scePowerGetBatteryLifePercent > , " scePowerGetBatteryLifePercent " } ,
{ 0x8EFB3FA2 , 0 , " scePowerGetBatteryLifeTime " } ,
{ 0x28E12023 , 0 , " scePowerGetBatteryTemp " } ,
{ 0x862AE1A6 , 0 , " scePowerGetBatteryElec " } ,
{ 0x483CE86B , 0 , " scePowerGetBatteryVolt " } ,
{ 0x23436A4A , 0 , " scePowerGetInnerTemp " } ,
{ 0x0CD21B1F , 0 , " scePowerSetPowerSwMode " } ,
{ 0x165CE085 , 0 , " scePowerGetPowerSwMode " } ,
{ 0xD6D016EF , 0 , " scePowerLock " } ,
{ 0xCA3D34C1 , 0 , " scePowerUnlock " } ,
{ 0xDB62C9CF , 0 , " scePowerCancelRequest " } ,
{ 0x7FA406DD , 0 , " scePowerIsRequest " } ,
{ 0x2B7C7CF4 , 0 , " scePowerRequestStandby " } ,
{ 0xAC32C9CC , 0 , " scePowerRequestSuspend " } ,
{ 0x2875994B , 0 , " scePower_2875994B " } ,
{ 0x0074EF9B , 0 , " scePowerGetResumeCount " } ,
{ 0xDFA8BAF8 , & WrapI_I < scePowerUnregisterCallback > , " scePowerUnregisterCallback " } ,
2012-11-11 22:50:48 +01:00
{ 0xDB9D28DD , & WrapI_I < scePowerUnregisterCallback > , " scePowerUnregitserCallback " } , //haha
2012-11-11 21:32:44 +00:00
{ 0x843FBF43 , 0 , " scePowerSetCpuClockFrequency " } ,
{ 0xB8D7B3FB , 0 , " scePowerSetBusClockFrequency " } ,
{ 0xFEE03A2F , 0 , " scePowerGetCpuClockFrequency " } ,
{ 0x478FE6F5 , 0 , " scePowerGetBusClockFrequency " } ,
{ 0xFDB5BFE9 , scePowerGetCpuClockFrequencyInt , " scePowerGetCpuClockFrequencyInt " } ,
2012-11-12 00:04:57 +01:00
{ 0xBD681969 , scePowerGetBusClockFrequencyInt , " scePowerGetBusClockFrequencyInt " } ,
2012-11-11 21:32:44 +00:00
{ 0xB1A52C83 , 0 , " scePowerGetCpuClockFrequencyFloat " } ,
{ 0x9BADB3EB , 0 , " scePowerGetBusClockFrequencyFloat " } ,
{ 0x737486F2 , & WrapV_UUU < scePowerSetClockFrequency > , " scePowerSetClockFrequency " } ,
2012-11-12 00:04:57 +01:00
{ 0x34f9c463 , scePowerGetPllClockFrequencyInt , " scePowerGetPllClockFrequencyInt " } ,
2012-11-11 21:32:44 +00:00
{ 0xea382a27 , 0 , " scePowerGetPllClockFrequencyFloat " } ,
2012-11-14 18:52:06 +00:00
{ 0xebd177d6 , & WrapV_UUU < scePowerSetClockFrequency > , " scePower_driver_EBD177D6 " } , //TODO: used in a few places, jpcsp says is the same as scePowerSetClockFrequency
2012-11-07 15:44:13 +01:00
{ 0x469989ad , 0 , " scePower_469989ad " } ,
{ 0xa85880d0 , 0 , " scePower_a85880d0 " } ,
2012-11-01 16:19:01 +01:00
} ;
//890129c in tyshooter looks bogus
const HLEFunction sceSuspendForUser [ ] =
{
2012-11-11 21:32:44 +00:00
{ 0xEADB1BD7 , & WrapI_I < sceKernelPowerLock > , " sceKernelPowerLock " } , //(int param) set param to 0
{ 0x3AEE7261 , & WrapI_I < sceKernelPowerUnlock > , " sceKernelPowerUnlock " } , //(int param) set param to 0
{ 0x090ccb3f , & WrapI_I < sceKernelPowerTick > , " sceKernelPowerTick " } ,
// There's an extra 4MB that can be allocated, which seems to be "volatile". These functions
// let you grab it.
{ 0xa14f40b2 , & WrapI_III < sceKernelVolatileMemTryLock > , " sceKernelVolatileMemTryLock " } ,
{ 0xa569e425 , & WrapI_I < sceKernelVolatileMemUnlock > , " sceKernelVolatileMemUnlock " } ,
{ 0x3e0271d3 , & WrapI_III < sceKernelVolatileMemLock > , " sceKernelVolatileMemLock " } , //when "acquiring mem pool" (fired up)
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
}