/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.HLE.modules;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLELogging;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.kernel.types.SceKernelErrors;
import jpcsp.HLE.kernel.types.SceKernelThreadInfo;
import jpcsp.HLE.Modules;
import jpcsp.hardware.Battery;
import jpcsp.hardware.Model;
import org.apache.log4j.Logger;
public class scePower extends HLEModule {
public static Logger log = Modules.getLogger("scePower");
/**
* Power callback flags
*/
// indicates the power switch it pushed, putting the unit into suspend mode
public static final int PSP_POWER_CB_POWER_SWITCH = 0x80000000;
// indicates the hold switch is on
public static final int PSP_POWER_CB_HOLD_SWITCH = 0x40000000;
// what is standby mode?
public static final int PSP_POWER_CB_STANDBY = 0x00080000;
// indicates the resume process has been completed (only seems to be triggered when another event happens)
public static final int PSP_POWER_CB_RESUME_COMPLETE = 0x00040000;
// indicates the unit is resuming from suspend mode
public static final int PSP_POWER_CB_RESUMING = 0x00020000;
// indicates the unit is suspending, seems to occur due to inactivity
public static final int PSP_POWER_CB_SUSPENDING = 0x00010000;
// indicates the unit is plugged into an AC outlet
public static final int PSP_POWER_CB_AC_POWER = 0x00001000;
// indicates the battery charge level is low
public static final int PSP_POWER_CB_BATTERY_LOW = 0x00000100;
// indicates there is a battery present in the unit
public static final int PSP_POWER_CB_BATTERY_EXIST = 0x00000080;
// unknown
public static final int PSP_POWER_CB_BATTPOWER = 0x0000007F;
/**
* Power callback slots
*/
public static final int PSP_POWER_CB_SLOT_AUTO = -1;
protected int[] powerCBSlots = new int[16];
// PLL clock:
// Operates at fixed rates of 148MHz, 190MHz, 222MHz, 266MHz, 333MHz.
// Starts at 222MHz.
protected int pllClock = 222;
// CPU clock:
// Operates at variable rates from 1MHz to 333MHz.
// Starts at 222MHz.
// Note: Cannot have a higher frequency than the PLL clock's frequency.
protected int cpuClock = 222;
// BUS clock:
// Operates at variable rates from 37MHz to 166MHz.
// Starts at 111MHz.
// Note: Cannot have a higher frequency than 1/2 of the PLL clock's frequency
// or lower than 1/4 of the PLL clock's frequency.
protected int busClock = 111;
protected static final int backlightMaximum = 4;
@HLEUnimplemented
@HLEFunction(nid = 0x2B51FE2F, version = 150)
public int scePower_2B51FE2F() {
return 0;
}
@HLEFunction(nid = 0x442BFBAC, version = 150)
public int scePowerGetBacklightMaximum() {
return backlightMaximum;
}
@HLELogging(level="trace")
@HLEFunction(nid = 0xEFD3C963, version = 150)
public int scePowerTick(int flag) {
return Modules.sceSuspendForUserModule.hleKernelPowerTick(flag);
}
@HLEUnimplemented
@HLEFunction(nid = 0xEDC13FE5, version = 150)
public int scePowerGetIdleTimer() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x7F30B3B1, version = 150)
public int scePowerIdleTimerEnable() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x972CE941, version = 150)
public int scePowerIdleTimerDisable() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x27F3292C, version = 150)
public int scePowerBatteryUpdateInfo() {
return 0;
}
@HLEFunction(nid = 0xE8E4E204, version = 150)
public int scePowerGetForceSuspendCapacity() {
int forceSuspendCapacity = (Battery.getForceSuspendPercent() * Battery.getFullCapacity()) / 100;
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetForceSuspendCapacity returning %d mAh", forceSuspendCapacity));
}
return forceSuspendCapacity;
}
@HLEFunction(nid = 0xB999184C, version = 150)
public int scePowerGetLowBatteryCapacity() {
int lowBatteryCapacity = (Battery.getLowPercent() * Battery.getFullCapacity()) / 100;
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetLowBatteryCapacity returning %d mAh", lowBatteryCapacity));
}
return lowBatteryCapacity;
}
@HLEFunction(nid = 0x87440F5E, version = 150)
public boolean scePowerIsPowerOnline() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerIsPowerOnline returning %b", Battery.isPluggedIn()));
}
return Battery.isPluggedIn();
}
@HLEFunction(nid = 0x0AFD0D8B, version = 150)
public boolean scePowerIsBatteryExist() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerIsBatteryExist returning %b", Battery.isPresent()));
}
return Battery.isPresent();
}
@HLEFunction(nid = 0x1E490401, version = 150)
public boolean scePowerIsBatteryCharging() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerIsBatteryCharging returning %b", Battery.isCharging()));
}
return Battery.isCharging();
}
@HLEFunction(nid = 0xB4432BC8, version = 150)
public int scePowerGetBatteryChargingStatus() {
int status = 0;
if (Battery.isPresent()) {
status |= PSP_POWER_CB_BATTERY_EXIST;
}
if (Battery.isPluggedIn()) {
status |= PSP_POWER_CB_AC_POWER;
}
if (Battery.isCharging()) {
// I don't know exactly what to return under PSP_POWER_CB_BATTPOWER
status |= PSP_POWER_CB_BATTPOWER;
}
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryChargingStatus returning 0x%X", status));
}
return status;
}
@HLEFunction(nid = 0xD3075926, version = 150)
public boolean scePowerIsLowBattery() {
boolean isLow = Battery.getCurrentPowerPercent() <= Battery.getLowPercent();
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerIsLowBattery returning %b", isLow));
}
return isLow;
}
/**
* Check if suspend is requided
*
* @note: This function return 1 only when
* the battery charge is low and
* go in suspend mode!
*
* @return 1 if suspend is requided, otherwise 0
*/
@HLEFunction(nid = 0x78A1A796, version = 150)
public boolean scePowerIsSuspendRequired() {
boolean isSuspendRequired = Battery.getCurrentPowerPercent() <= Battery.getForceSuspendPercent();
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerIsSuspendRequired returning %b", isSuspendRequired));
}
return isSuspendRequired;
}
@HLEFunction(nid = 0x94F5A53F, version = 150)
public int scePowerGetBatteryRemainCapacity() {
int batteryRemainCapacity = (Battery.getCurrentPowerPercent() * Battery.getFullCapacity()) / 100;
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryRemainCapacity returning %d mAh", batteryRemainCapacity));
}
return batteryRemainCapacity;
}
@HLEFunction(nid = 0xFD18A0FF, version = 150)
public int scePowerGetBatteryFullCapacity() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryFullCapacity returning %d mAh", Battery.getFullCapacity()));
}
return Battery.getFullCapacity();
}
@HLEFunction(nid = 0x2085D15D, version = 150)
public int scePowerGetBatteryLifePercent() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryLifePercent returning %d %%", Battery.getCurrentPowerPercent()));
}
return Battery.getCurrentPowerPercent();
}
@HLEFunction(nid = 0x8EFB3FA2, version = 150)
public int scePowerGetBatteryLifeTime() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryLifeTime returning %d", Battery.getLifeTime()));
}
return Battery.getLifeTime();
}
@HLEFunction(nid = 0x28E12023, version = 150)
public int scePowerGetBatteryTemp() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryTemp returning %d C", Battery.getTemperature()));
}
return Battery.getTemperature();
}
@HLEUnimplemented
@HLEFunction(nid = 0x862AE1A6, version = 150)
public int scePowerGetBatteryElec() {
return 0;
}
@HLEFunction(nid = 0x483CE86B, version = 150)
public int scePowerGetBatteryVolt() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBatteryVolt %d", Battery.getVoltage()));
}
return Battery.getVoltage();
}
@HLEUnimplemented
@HLEFunction(nid = 0x23436A4A, version = 150)
public int scePower_23436A4A() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x0CD21B1F, version = 150)
public int scePowerSetPowerSwMode() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x165CE085, version = 150)
public int scePowerGetPowerSwMode() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x23C31FFE, version = 150)
public int scePowerVolatileMemLock() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xFA97A599, version = 150)
public int scePowerVolatileMemTryLock() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xB3EDD801, version = 150)
public int scePowerVolatileMemUnlock() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xD6D016EF, version = 150)
public int scePowerLock() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xCA3D34C1, version = 150)
public int scePowerUnlock() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xDB62C9CF, version = 150)
public int scePowerCancelRequest() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x7FA406DD, version = 150)
public int scePowerIsRequest() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x2B7C7CF4, version = 150)
public int scePowerRequestStandby() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xAC32C9CC, version = 150)
public int scePowerRequestSuspend() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x2875994B, version = 150)
public int scePower_2875994B() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x3951AF53, version = 150)
public int scePowerWaitRequestCompletion() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x0074EF9B, version = 150)
public int scePowerGetResumeCount() {
return 0;
}
@HLELogging(level="info")
@HLEFunction(nid = 0x04B7766E, version = 150)
public int scePowerRegisterCallback(int slot, int uid) {
boolean notifyCallback = false;
int result;
// Multiple power callbacks (up to 16) can be assigned for multiple threads.
if (slot == PSP_POWER_CB_SLOT_AUTO) {
// Return ERROR_OUT_OF_MEMORY when no free slot found
result = SceKernelErrors.ERROR_OUT_OF_MEMORY;
for (int i = 0; i < powerCBSlots.length; i++) {
if (powerCBSlots[i] == 0) {
powerCBSlots[i] = uid;
result = i;
notifyCallback = true;
break;
}
}
} else if (slot >= 0 && slot < powerCBSlots.length) {
if (powerCBSlots[slot] == 0) {
powerCBSlots[slot] = uid;
result = 0;
notifyCallback = true;
} else {
result = SceKernelErrors.ERROR_ALREADY;
}
} else {
result = -1;
}
if (notifyCallback) {
ThreadManForUser threadMan = Modules.ThreadManForUserModule;
if (threadMan.hleKernelRegisterCallback(SceKernelThreadInfo.THREAD_CALLBACK_POWER, uid)) {
// Start by notifying the POWER callback that we're using AC power.
threadMan.hleKernelNotifyCallback(SceKernelThreadInfo.THREAD_CALLBACK_POWER, uid, PSP_POWER_CB_AC_POWER);
}
}
return result;
}
@HLELogging(level="info")
@HLEFunction(nid = 0xDFA8BAF8, version = 150)
public int scePowerUnregisterCallback(int slot) {
if (slot < 0 || slot >= powerCBSlots.length) {
return -1;
}
if (powerCBSlots[slot] != 0) {
ThreadManForUser threadMan = Modules.ThreadManForUserModule;
threadMan.hleKernelUnRegisterCallback(SceKernelThreadInfo.THREAD_CALLBACK_POWER, powerCBSlots[slot]);
powerCBSlots[slot] = 0;
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xDB9D28DD, version = 150)
public int scePowerUnregisterCallback() {
return 0;
}
@HLEFunction(nid = 0x843FBF43, version = 150, checkInsideInterrupt = true)
public int scePowerSetCpuClockFrequency(int freq) {
cpuClock = freq;
return 0;
}
@HLEFunction(nid = 0xB8D7B3FB, version = 150, checkInsideInterrupt = true)
public int scePowerSetBusClockFrequency(int freq) {
busClock = freq;
return 0;
}
@HLEFunction(nid = 0xFEE03A2F, version = 150)
public int scePowerGetCpuClockFrequency() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetCpuClockFrequency returning 0x%X", cpuClock));
}
return cpuClock;
}
@HLEFunction(nid = 0x478FE6F5, version = 150)
public int scePowerGetBusClockFrequency() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBusClockFrequency returning 0x%X", busClock));
}
return busClock;
}
@HLEFunction(nid = 0xFDB5BFE9, version = 150)
public int scePowerGetCpuClockFrequencyInt() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetCpuClockFrequencyInt returning 0x%X", cpuClock));
}
return cpuClock;
}
@HLEFunction(nid = 0xBD681969, version = 150)
public int scePowerGetBusClockFrequencyInt() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBusClockFrequencyInt returning 0x%X", busClock));
}
return busClock;
}
@HLEFunction(nid = 0x34F9C463, version = 150)
public int scePowerGetPllClockFrequencyInt() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetPllClockFrequencyInt returning 0x%X", pllClock));
}
return pllClock;
}
@HLEFunction(nid = 0xB1A52C83, version = 150)
public float scePowerGetCpuClockFrequencyFloat() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetCpuClockFrequencyFloat returning %f", (float) cpuClock));
}
return (float) cpuClock;
}
@HLEFunction(nid = 0x9BADB3EB, version = 150)
public float scePowerGetBusClockFrequencyFloat() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetBusClockFrequencyFloat returning %f", (float) busClock));
}
return (float) busClock;
}
@HLEFunction(nid = 0xEA382A27, version = 150)
public float scePowerGetPllClockFrequencyFloat() {
if (log.isDebugEnabled()) {
log.debug(String.format("scePowerGetPllClockFrequencyFloat returning %f", (float) pllClock));
}
return (float) pllClock;
}
@HLEFunction(nid = 0x737486F2, version = 150)
public int scePowerSetClockFrequency(int pllClock, int cpuClock, int busClock) {
if (cpuClock == 0 || cpuClock > 333) {
log.warn(String.format("scePowerSetClockFrequency invalid frequency pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
return SceKernelErrors.ERROR_INVALID_VALUE;
}
log.info(String.format("scePowerSetClockFrequency pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
this.cpuClock = cpuClock;
this.busClock = busClock;
if (this.pllClock != pllClock) {
this.pllClock = pllClock;
Modules.ThreadManForUserModule.hleKernelDelayThread(150000, false);
}
return 0;
}
@HLEFunction(nid = 0xEBD177D6, version = 150)
public int scePower_EBD177D6(int pllClock, int cpuClock, int busClock) {
// Identical to scePowerSetClockFrequency.
if (cpuClock == 0 || cpuClock > 333) {
log.warn(String.format("scePower_EBD177D6 invalid frequency pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
return SceKernelErrors.ERROR_INVALID_VALUE;
}
log.info(String.format("scePower_EBD177D6 pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
this.cpuClock = cpuClock;
this.busClock = busClock;
if (this.pllClock != pllClock) {
this.pllClock = pllClock;
Modules.ThreadManForUserModule.hleKernelDelayThread(150000, false);
}
return 0;
}
@HLEFunction(nid = 0x469989AD, version = 630)
public int scePower_469989AD(int pllClock, int cpuClock, int busClock) {
// Identical to scePowerSetClockFrequency.
if (cpuClock == 0 || cpuClock > 333) {
log.warn(String.format("scePower_469989AD invalid frequency pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
return SceKernelErrors.ERROR_INVALID_VALUE;
}
log.info(String.format("scePower_469989AD pllClock %d cpuClock %d busClock %d",pllClock,cpuClock,busClock));
this.cpuClock = cpuClock;
this.busClock = busClock;
if (this.pllClock != pllClock) {
this.pllClock = pllClock;
Modules.ThreadManForUserModule.hleKernelDelayThread(150000, false);
}
return 0;
}
@HLEFunction(nid = 0xA85880D0, version = 630)
public boolean scePower_A85880D0() {
int model = Model.getModel();
// Returning 0 for a PSP fat, 1 otherwise
boolean result = model != Model.MODEL_PSP_FAT;
if (log.isDebugEnabled()) {
log.debug(String.format("scePower_A85880D0 returning %b", result));
}
return result;
}
@HLEUnimplemented
@HLEFunction(nid = 0xBA566CD0, version = 660)
public int scePowerSetWakeupCondition(int condition) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x3234844A, version = 150)
public int scePower_driver_3234844A() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x5F5006D2, version = 660)
public int scePower_driver_5F5006D2() {
return scePower_driver_3234844A();
}
@HLEUnimplemented
@HLEFunction(nid = 0x315B8CB6, version = 150)
public int scePowerUnregisterCallback_660() {
return 0;
}
@HLELogging(level="info")
@HLEFunction(nid = 0x766CD857, version = 150)
public int scePowerRegisterCallback_660(int slot, int uid) {
return scePowerRegisterCallback(slot, uid);
}
}