mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-06 19:16:21 +02:00
Merge pull request #111 from unknownbrackets/umd-fixes
Fix sceUmdWaitDriveStatCB()
This commit is contained in:
commit
edee65aeb3
5 files changed
+196
-63
No files matched your search
@@ -108,6 +108,10 @@ template<void func(int, int)> void WrapV_II() {
|
||||
func(PARAM(0), PARAM(1));
|
||||
}
|
||||
|
||||
template<void func(u32, const char *)> void WrapV_UC() {
|
||||
func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32)> void WrapU_UU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1));
|
||||
RETURN(retval);
|
||||
|
||||
@@ -374,8 +374,15 @@ void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr)
|
||||
if (timeoutPtr == 0 || mutexWaitTimer == 0)
|
||||
return;
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
int micro = (int) Memory::Read_U32(timeoutPtr);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (micro <= 3)
|
||||
micro = 15;
|
||||
else if (micro <= 249)
|
||||
micro = 250;
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), mutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
@@ -701,7 +708,7 @@ void __KernelWaitLwMutex(LwMutex *mutex, u32 timeoutPtr)
|
||||
else if (micro <= 249)
|
||||
micro = 250;
|
||||
|
||||
// This should call __KernelMutexTimeout() later, unless we cancel it.
|
||||
// This should call __KernelLwMutexTimeout() later, unless we cancel it.
|
||||
CoreTiming::ScheduleEvent(usToCycles(micro), lwMutexWaitTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
|
||||
@@ -608,7 +608,7 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, int retval)
|
||||
// Only run when you can safely accept a context switch
|
||||
// Triggers a waitable event, that is, it wakes up all threads that waits for it
|
||||
// If any changes were made, it will context switch
|
||||
bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
|
||||
bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, bool dontSwitch)
|
||||
{
|
||||
bool doneAnything = false;
|
||||
|
||||
@@ -621,6 +621,8 @@ bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
|
||||
{
|
||||
// This thread was waiting for the triggered object.
|
||||
__KernelResumeThreadFromWait(t);
|
||||
if (useRetVal)
|
||||
t->setReturnValue(retVal);
|
||||
doneAnything = true;
|
||||
}
|
||||
}
|
||||
@@ -639,6 +641,16 @@ bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch)
|
||||
{
|
||||
return __KernelTriggerWait(type, id, false, 0, dontSwitch);
|
||||
}
|
||||
|
||||
bool __KernelTriggerWait(WaitType type, int id, int retVal, bool dontSwitch)
|
||||
{
|
||||
return __KernelTriggerWait(type, id, true, retVal, dontSwitch);
|
||||
}
|
||||
|
||||
// makes the current thread wait for an event
|
||||
void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 timeoutPtr, bool processCallbacks)
|
||||
{
|
||||
@@ -1799,7 +1811,8 @@ bool __KernelCheckCallbacks() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
void sceKernelCheckCallback() {
|
||||
bool __KernelForceCallbacks()
|
||||
{
|
||||
Thread *curThread = __GetCurrentThread();
|
||||
|
||||
// This thread can now process callbacks.
|
||||
@@ -1810,6 +1823,14 @@ void sceKernelCheckCallback() {
|
||||
// Note - same thread as above - checking callbacks may switch threads.
|
||||
curThread->isProcessingCallbacks = false;
|
||||
|
||||
return callbacksProcessed;
|
||||
}
|
||||
|
||||
void sceKernelCheckCallback() {
|
||||
Thread *curThread = __GetCurrentThread();
|
||||
|
||||
bool callbacksProcessed = __KernelForceCallbacks();
|
||||
|
||||
if (callbacksProcessed) {
|
||||
curThread->setReturnValue(1);
|
||||
ERROR_LOG(HLE,"sceKernelCheckCallback() - processed a callback.");
|
||||
@@ -1856,7 +1877,7 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID threadId, SceUID
|
||||
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
|
||||
if (!cb) {
|
||||
// Yeah, we're screwed, this shouldn't happen.
|
||||
ERROR_LOG(HLE, "__KernelNotifyCallback - invalid callback 0");
|
||||
ERROR_LOG(HLE, "__KernelNotifyCallback - invalid callback %08x", cbId);
|
||||
return;
|
||||
}
|
||||
cb->nc.notifyCount++;
|
||||
|
||||
@@ -104,6 +104,7 @@ void __KernelLoadContext(ThreadContext *ctx);
|
||||
|
||||
// TODO: Replace this with __KernelResumeThread over time as it's misguided.
|
||||
bool __KernelTriggerWait(WaitType type, int id, bool dontSwitch = false);
|
||||
bool __KernelTriggerWait(WaitType type, int id, int retVal, bool dontSwitch);
|
||||
u32 __KernelResumeThreadFromWait(SceUID threadID); // can return an error value
|
||||
u32 __KernelResumeThreadFromWait(SceUID threadID, int retval);
|
||||
|
||||
@@ -163,6 +164,7 @@ bool __KernelInCallback();
|
||||
|
||||
// Should be called by (nearly) all ...CB functions.
|
||||
bool __KernelCheckCallbacks();
|
||||
bool __KernelForceCallbacks();
|
||||
class Thread;
|
||||
void __KernelSwitchContext(Thread *target, const char *reason);
|
||||
bool __KernelExecutePendingMipsCalls();
|
||||
|
||||
+157
-58
@@ -17,9 +17,12 @@
|
||||
|
||||
#include "HLE.h"
|
||||
#include "../MIPS/MIPS.h"
|
||||
#include "../../Core/CoreTiming.h"
|
||||
#include "sceUmd.h"
|
||||
#include "sceKernelThread.h"
|
||||
|
||||
const int PSP_ERROR_UMD_INVALID_PARAM = 0x80010016;
|
||||
|
||||
#define UMD_NOT_PRESENT 0x01
|
||||
#define UMD_PRESENT 0x02
|
||||
#define UMD_CHANGED 0x04
|
||||
@@ -32,6 +35,7 @@ u8 umdActivated = 1;
|
||||
u32 umdStatus = 0;
|
||||
u32 umdErrorStat = 0;
|
||||
static int driveCBId= -1;
|
||||
int umdStatTimer = 0;
|
||||
|
||||
|
||||
#define PSP_UMD_TYPE_GAME 0x10
|
||||
@@ -39,7 +43,8 @@ static int driveCBId= -1;
|
||||
#define PSP_UMD_TYPE_AUDIO 0x40
|
||||
|
||||
struct PspUmdInfo {
|
||||
int type;
|
||||
u32 size;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
|
||||
@@ -76,68 +81,121 @@ void __KernelUmdDeactivate()
|
||||
|
||||
|
||||
//int sceUmdCheckMedium(int a);
|
||||
void sceUmdCheckMedium()
|
||||
int sceUmdCheckMedium()
|
||||
{
|
||||
DEBUG_LOG(HLE,"1=sceUmdCheckMedium(?)");
|
||||
//ignore PARAM(0)
|
||||
RETURN(1); //non-zero: disc in drive
|
||||
return 1; //non-zero: disc in drive
|
||||
}
|
||||
|
||||
void sceUmdGetDiscInfo()
|
||||
u32 sceUmdGetDiscInfo(u32 infoAddr)
|
||||
{
|
||||
u32 infoAddr = PARAM(0);
|
||||
ERROR_LOG(HLE,"sceUmdGetDiscInfo(%08x)", infoAddr);
|
||||
PspUmdInfo info;
|
||||
info.type = PSP_UMD_TYPE_GAME;
|
||||
DEBUG_LOG(HLE, "sceUmdGetDiscInfo(%08x)", infoAddr);
|
||||
|
||||
if (Memory::IsValidAddress(infoAddr))
|
||||
{
|
||||
PspUmdInfo info;
|
||||
Memory::ReadStruct(infoAddr, &info);
|
||||
if (info.size != 8)
|
||||
return PSP_ERROR_UMD_INVALID_PARAM;
|
||||
|
||||
info.type = PSP_UMD_TYPE_GAME;
|
||||
Memory::WriteStruct(infoAddr, &info);
|
||||
return 0;
|
||||
}
|
||||
RETURN(0);
|
||||
else
|
||||
return PSP_ERROR_UMD_INVALID_PARAM;
|
||||
}
|
||||
|
||||
u32 sceUmdActivate(u32 unknown, const char *name)
|
||||
void sceUmdActivate(u32 unknown, const char *name)
|
||||
{
|
||||
u32 retVal = 0;
|
||||
if (unknown < 1 || unknown > 2)
|
||||
{
|
||||
RETURN(PSP_ERROR_UMD_INVALID_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = umdActivated == 0;
|
||||
__KernelUmdActivate();
|
||||
DEBUG_LOG(HLE,"%i=sceUmdActivate(%08x, %s)", retVal, unknown, name);
|
||||
|
||||
if (unknown == 1)
|
||||
{
|
||||
DEBUG_LOG(HLE, "0=sceUmdActivate(%d, %s)", unknown, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "UNTESTED 0=sceUmdActivate(%d, %s)", unknown, name);
|
||||
}
|
||||
|
||||
u32 notifyArg = UMD_PRESENT | UMD_READABLE;
|
||||
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
|
||||
return retVal;
|
||||
RETURN(0);
|
||||
|
||||
if (changed)
|
||||
__KernelReSchedule("umd activated");
|
||||
}
|
||||
|
||||
u32 sceUmdDeactivate(u32 unknown, const char *name)
|
||||
void sceUmdDeactivate(u32 unknown, const char *name)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceUmdDeactivate()");
|
||||
u8 triggerCallback = umdActivated;
|
||||
// Why 18? No idea.
|
||||
if (unknown < 0 || unknown > 18)
|
||||
{
|
||||
RETURN(PSP_ERROR_UMD_INVALID_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = umdActivated != 0;
|
||||
__KernelUmdDeactivate();
|
||||
|
||||
if (triggerCallback) {
|
||||
u32 notifyArg = UMD_PRESENT | UMD_READY;
|
||||
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
|
||||
if (unknown == 1)
|
||||
{
|
||||
DEBUG_LOG(HLE, "0=sceUmdDeactivate(%d, %s)", unknown, name);
|
||||
}
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "UNTESTED 0=sceUmdDeactivate(%d, %s)", unknown, name);
|
||||
}
|
||||
|
||||
u32 notifyArg = UMD_PRESENT | UMD_READY;
|
||||
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
|
||||
RETURN(0);
|
||||
|
||||
if (changed)
|
||||
__KernelReSchedule("umd deactivated");
|
||||
}
|
||||
|
||||
u32 sceUmdRegisterUMDCallBack(u32 cbId)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdRegisterUMDCallback(id=%i)",PARAM(0));
|
||||
if (driveCBId == -1)
|
||||
{
|
||||
driveCBId = cbId;
|
||||
}
|
||||
int retVal;
|
||||
|
||||
// TODO: If the callback is invalid, return PSP_ERROR_UMD_INVALID_PARAM.
|
||||
if (cbId == 0)
|
||||
retVal = PSP_ERROR_UMD_INVALID_PARAM;
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE," 0=sceUmdRegisterUMDCallback(id=%i) callback overwrite attempt",PARAM(0));
|
||||
retVal = __KernelRegisterCallback(THREAD_CALLBACK_UMD, cbId);
|
||||
driveCBId = cbId;
|
||||
}
|
||||
return __KernelRegisterCallback(THREAD_CALLBACK_UMD, cbId);
|
||||
|
||||
DEBUG_LOG(HLE, "%d=sceUmdRegisterUMDCallback(id=%08x)", retVal, cbId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u32 sceUmdUnRegisterUMDCallBack(u32 cbId)
|
||||
{
|
||||
DEBUG_LOG(HLE,"0=sceUmdUnRegisterUMDCallBack(id=%i)",PARAM(0));
|
||||
driveCBId = -1;
|
||||
return __KernelUnregisterCallback(THREAD_CALLBACK_UMD, cbId);
|
||||
u32 retVal;
|
||||
|
||||
if (cbId != driveCBId)
|
||||
retVal = PSP_ERROR_UMD_INVALID_PARAM;
|
||||
else
|
||||
{
|
||||
retVal = cbId;
|
||||
driveCBId = -1;
|
||||
__KernelUnregisterCallback(THREAD_CALLBACK_UMD, cbId);
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u32 sceUmdGetDriveStat()
|
||||
@@ -148,6 +206,31 @@ u32 sceUmdGetDriveStat()
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void __UmdStatTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
u32 error;
|
||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_UMD, error);
|
||||
// Assuming it's still waiting.
|
||||
if (waitID == 1)
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
void __UmdWaitStat(u32 timeout)
|
||||
{
|
||||
if (umdStatTimer == 0)
|
||||
umdStatTimer = CoreTiming::RegisterEvent("MutexTimeout", &__UmdStatTimeout);
|
||||
|
||||
// This happens to be how the hardware seems to time things.
|
||||
if (timeout <= 4)
|
||||
timeout = 15;
|
||||
else if (timeout <= 215)
|
||||
timeout = 250;
|
||||
|
||||
CoreTiming::ScheduleEvent(usToCycles((int) timeout), umdStatTimer, __KernelGetCurThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a drive to reach a certain state
|
||||
*
|
||||
@@ -155,48 +238,64 @@ u32 sceUmdGetDriveStat()
|
||||
* @return < 0 on error
|
||||
*
|
||||
*/
|
||||
void sceUmdWaitDriveStat()
|
||||
void sceUmdWaitDriveStat(u32 stat)
|
||||
{
|
||||
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);
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStat(stat = %08x)", stat);
|
||||
RETURN(0);
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0)
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0);
|
||||
}
|
||||
|
||||
void sceUmdWaitDriveStatWithTimer()
|
||||
void sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout)
|
||||
{
|
||||
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);
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d)", stat, timeout);
|
||||
RETURN(0);
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0)
|
||||
{
|
||||
__UmdWaitStat(timeout);
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sceUmdWaitDriveStatCB()
|
||||
void sceUmdWaitDriveStatCB(u32 stat, u32 timeout)
|
||||
{
|
||||
u32 stat = PARAM(0);
|
||||
DEBUG_LOG(HLE,"HACK 0=sceUmdWaitDriveStatCB(stat = %08x)", stat);
|
||||
// Immediately notify
|
||||
RETURN(0);
|
||||
RETURN(0);
|
||||
|
||||
if (driveCBId != -1)
|
||||
{
|
||||
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, driveCBId, __KernelUmdGetState()&stat);
|
||||
DEBUG_LOG(HLE,"0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout);
|
||||
|
||||
bool callbacksProcessed = __KernelForceCallbacks();
|
||||
if (callbacksProcessed)
|
||||
__KernelExecutePendingMipsCalls();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "HACK 0=sceUmdWaitDriveStatCB(stat = %08x) attempting to call unset callback", stat);
|
||||
WARN_LOG(HLE, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d) without callback", stat, timeout);
|
||||
}
|
||||
|
||||
if ((stat & __KernelUmdGetState()) == 0)
|
||||
{
|
||||
if (timeout == 0)
|
||||
timeout = 8000;
|
||||
|
||||
__UmdWaitStat(timeout);
|
||||
__KernelWaitCurThread(WAITTYPE_UMD, 1, stat, 0, true);
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceUmdCancelWaitDriveStat()
|
||||
{
|
||||
u32 stat = PARAM(0);
|
||||
ERROR_LOG(HLE,"UNIMPL 0=sceUmdCancelWaitDriveStat(stat = %08x)", stat);
|
||||
DEBUG_LOG(HLE,"0=sceUmdCancelWaitDriveStat()");
|
||||
RETURN(0);
|
||||
|
||||
__KernelTriggerWait(WAITTYPE_UMD, 1, SCE_KERNEL_ERROR_WAIT_CANCEL, false);
|
||||
// TODO: We should call UnscheduleEvent() event here?
|
||||
// But it's not often used anyway, and worst-case it will just do nothing unless it waits again.
|
||||
}
|
||||
|
||||
u32 sceUmdGetErrorStat()
|
||||
@@ -208,17 +307,17 @@ u32 sceUmdGetErrorStat()
|
||||
|
||||
const HLEFunction sceUmdUser[] =
|
||||
{
|
||||
{0xC6183D47,&WrapU_UC<sceUmdActivate>,"sceUmdActivate"},
|
||||
{0xC6183D47,WrapV_UC<sceUmdActivate>,"sceUmdActivate"},
|
||||
{0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"},
|
||||
{0x46EBB729,sceUmdCheckMedium,"sceUmdCheckMedium"},
|
||||
{0xE83742BA,&WrapU_UC<sceUmdDeactivate>,"sceUmdDeactivate"},
|
||||
{0x8EF08FCE,sceUmdWaitDriveStat,"sceUmdWaitDriveStat"},
|
||||
{0x56202973,sceUmdWaitDriveStatWithTimer,"sceUmdWaitDriveStatWithTimer"},
|
||||
{0x4A9E5E29,sceUmdWaitDriveStatCB,"sceUmdWaitDriveStatCB"},
|
||||
{0x46EBB729,WrapI_V<sceUmdCheckMedium>,"sceUmdCheckMedium"},
|
||||
{0xE83742BA,WrapV_UC<sceUmdDeactivate>,"sceUmdDeactivate"},
|
||||
{0x8EF08FCE,WrapV_U<sceUmdWaitDriveStat>,"sceUmdWaitDriveStat"},
|
||||
{0x56202973,WrapV_UU<sceUmdWaitDriveStatWithTimer>,"sceUmdWaitDriveStatWithTimer"},
|
||||
{0x4A9E5E29,WrapV_UU<sceUmdWaitDriveStatCB>,"sceUmdWaitDriveStatCB"},
|
||||
{0x6af9b50a,sceUmdCancelWaitDriveStat,"sceUmdCancelWaitDriveStat"},
|
||||
{0x6B4A146C,&WrapU_V<sceUmdGetDriveStat>,"sceUmdGetDriveStat"},
|
||||
{0x20628E6F,&WrapU_V<sceUmdGetErrorStat>,"sceUmdGetErrorStat"},
|
||||
{0x340B7686,sceUmdGetDiscInfo,"sceUmdGetDiscInfo"},
|
||||
{0x340B7686,WrapU_U<sceUmdGetDiscInfo>,"sceUmdGetDiscInfo"},
|
||||
{0xAEE7404D,&WrapU_U<sceUmdRegisterUMDCallBack>,"sceUmdRegisterUMDCallBack"},
|
||||
{0xBD2BDE07,&WrapU_U<sceUmdUnRegisterUMDCallBack>,"sceUmdUnRegisterUMDCallBack"},
|
||||
{0x87533940,0,"sceUmdReplaceProhibit"}, // ??? sounds bogus
|
||||
|
||||
Reference in new issue
Block a user