// 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 // the Free Software Foundation, version 2.0 or later versions. // This program 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 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/. #include "HLE.h" #include "../MIPS/MIPS.h" #include "sceUmd.h" #include "sceKernelThread.h" #define UMD_NOT_PRESENT 0x01 #define UMD_PRESENT 0x02 #define UMD_CHANGED 0x04 #define UMD_NOT_READY 0x08 #define UMD_READY 0x10 #define UMD_READABLE 0x20 u8 umdActivated = 1; u32 umdStatus = 0; u32 umdErrorStat = 0; static int driveCBId= -1; #define PSP_UMD_TYPE_GAME 0x10 #define PSP_UMD_TYPE_VIDEO 0x20 #define PSP_UMD_TYPE_AUDIO 0x40 struct PspUmdInfo { int type; }; void __UmdInit() { umdActivated = 1; umdStatus = 0; umdErrorStat = 0; driveCBId = -1; } u8 __KernelUmdGetState() { u8 state = UMD_PRESENT; if (umdActivated) { state |= UMD_READY; state |= UMD_READABLE; } else state |= UMD_NOT_READY; return state; } void __KernelUmdActivate() { umdActivated = 1; } void __KernelUmdDeactivate() { umdActivated = 0; } // typedef int (*UmdCallback)(int unknown, int event); //int sceUmdCheckMedium(int a); void sceUmdCheckMedium() { DEBUG_LOG(HLE,"1=sceUmdCheckMedium(?)"); //ignore PARAM(0) RETURN(1); //non-zero: disc in drive } void sceUmdGetDiscInfo() { u32 infoAddr = PARAM(0); ERROR_LOG(HLE,"sceUmdGetDiscInfo(%08x)", infoAddr); PspUmdInfo info; info.type = PSP_UMD_TYPE_GAME; if (Memory::IsValidAddress(infoAddr)) { Memory::WriteStruct(infoAddr, &info); } RETURN(0); } u32 sceUmdActivate(u32 unknown, const char *name) { u32 retVal = 0; __KernelUmdActivate(); DEBUG_LOG(HLE,"%i=sceUmdActivate(%08x, %s)", retVal, unknown, name); u32 notifyArg = UMD_PRESENT | UMD_READABLE; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); return retVal; } u32 sceUmdDeactivate(u32 unknown, const char *name) { DEBUG_LOG(HLE,"sceUmdDeactivate()"); u8 triggerCallback = umdActivated; __KernelUmdDeactivate(); if (triggerCallback) { u32 notifyArg = UMD_PRESENT | UMD_READY; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); } return 0; } u32 sceUmdRegisterUMDCallBack(u32 cbId) { DEBUG_LOG(HLE,"0=sceUmdRegisterUMDCallback(id=%i)",PARAM(0)); if (driveCBId == -1) { driveCBId = cbId; } else { ERROR_LOG(HLE," 0=sceUmdRegisterUMDCallback(id=%i) callback overwrite attempt",PARAM(0)); } return __KernelRegisterCallback(THREAD_CALLBACK_UMD, cbId); } u32 sceUmdUnRegisterUMDCallBack(u32 cbId) { DEBUG_LOG(HLE,"0=sceUmdUnRegisterUMDCallBack(id=%i)",PARAM(0)); driveCBId = -1; return __KernelUnregisterCallback(THREAD_CALLBACK_UMD, cbId); } u32 sceUmdGetDriveStat() { //u32 retVal = PSP_UMD_INITED | PSP_UMD_READY | PSP_UMD_PRESENT; u32 retVal = __KernelUmdGetState(); DEBUG_LOG(HLE,"0x%02x=sceUmdGetDriveStat()",retVal); return retVal; } /** * Wait for a drive to reach a certain state * * @param stat - The drive stat to wait for. * @return < 0 on error * */ void sceUmdWaitDriveStat() { u32 stat = PARAM(0); DEBUG_LOG(HLE,"HACK 0=sceUmdWaitDriveStat(stat = %08x)", stat); if ((stat & __KernelUmdGetState()) != stat) __KernelWaitCurThread(WAITTYPE_UMD, 0, stat, 0, 0); //__KernelWaitCurThread(WAITTYPE_UMD, 0); RETURN(0); } void sceUmdWaitDriveStatWithTimer() { u32 stat = PARAM(0); u32 timeout = PARAM(1); DEBUG_LOG(HLE,"HACK 0=sceUmdWaitDriveStatWithTimer(stat = %08x)", stat); if ((stat & __KernelUmdGetState()) != stat) __KernelWaitCurThread(WAITTYPE_UMD, 0, stat, 0, 0); //__KernelWaitCurThread(WAITTYPE_UMD, 0); RETURN(0); } void sceUmdWaitDriveStatCB() { u32 stat = PARAM(0); DEBUG_LOG(HLE,"HACK 0=sceUmdWaitDriveStatCB(stat = %08x)", stat); // Immediately notify RETURN(0); if (driveCBId != -1) { __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, driveCBId, __KernelUmdGetState()&stat); } else { ERROR_LOG(HLE, "HACK 0=sceUmdWaitDriveStatCB(stat = %08x) attempting to call unset callback", stat); } RETURN(0); } void sceUmdCancelWaitDriveStat() { u32 stat = PARAM(0); ERROR_LOG(HLE,"UNIMPL 0=sceUmdCancelWaitDriveStat(stat = %08x)", stat); RETURN(0); } u32 sceUmdGetErrorStat() { DEBUG_LOG(HLE,"%i=sceUmdGetErrorStat()", umdErrorStat); return umdErrorStat; } const HLEFunction sceUmdUser[] = { {0xC6183D47,&WrapU_UC,"sceUmdActivate"}, {0x6B4A146C,&WrapU_V,"sceUmdGetDriveStat"}, {0x46EBB729,sceUmdCheckMedium,"sceUmdCheckMedium"}, {0xE83742BA,&WrapU_UC,"sceUmdDeactivate"}, {0x8EF08FCE,sceUmdWaitDriveStat,"sceUmdWaitDriveStat"}, {0x56202973,sceUmdWaitDriveStatWithTimer,"sceUmdWaitDriveStatWithTimer"}, {0x4A9E5E29,sceUmdWaitDriveStatCB,"sceUmdWaitDriveStatCB"}, {0x6af9b50a,sceUmdCancelWaitDriveStat,"sceUmdCancelWaitDriveStat"}, {0x6B4A146C,&WrapU_V,"sceUmdGetDriveStat"}, {0x20628E6F,&WrapU_V,"sceUmdGetErrorStat"}, {0x340B7686,sceUmdGetDiscInfo,"sceUmdGetDiscInfo"}, {0xAEE7404D,&WrapU_U,"sceUmdRegisterUMDCallBack"}, {0xBD2BDE07,&WrapU_U,"sceUmdUnRegisterUMDCallBack"}, {0x87533940,0,"sceUmdReplaceProhibit"}, // ??? sounds bogus }; void Register_sceUmdUser() { RegisterModule("sceUmdUser", ARRAY_SIZE(sceUmdUser), sceUmdUser); }