void sceUmdDeactivate(u32 unknown, const char *name) { // Why 18? No idea. if (unknown < 0 || unknown > 18) { RETURN(PSP_ERROR_UMD_INVALID_PARAM); return; } bool changed = umdActivated != 0; __KernelUmdDeactivate(); if (unknown == 1) { DEBUG_LOG(HLE, "0=sceUmdDeactivate(%d, %s)", unknown, name); } 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"); }
int scePowerRegisterCallback(int slot, int cbId) { DEBUG_LOG(HLE,"0=scePowerRegisterCallback(%i, %i)", slot, cbId); int foundSlot = -1; if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank for (int i=0; i < numberOfCBPowerSlots; i++) { if ((powerCbSlots[i]==0) && (foundSlot == POWER_CB_AUTO)) { // found an empty slot powerCbSlots[i] = cbId; foundSlot = i; } } } else { if (powerCbSlots[slot] == 0) { powerCbSlots[slot] = cbId; foundSlot = 0; } else { // slot already in use! foundSlot = POWER_CB_AUTO; } } if (foundSlot>=0) { __KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId); __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 } return foundSlot; }
void __KernelUmdDeactivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READY; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); CoreTiming::RemoveAllEvents(umdStatChangeEvent); __UmdStatChange(0, 0); }
void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; __KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg); // Don't activate immediately, take time to "spin up." CoreTiming::RemoveAllEvents(umdStatChangeEvent); CoreTiming::ScheduleEvent(usToCycles(MICRO_DELAY_ACTIVATE), umdStatChangeEvent, 1); }
int scePowerRegisterCallback(int slot, int cbId) { DEBUG_LOG(HLE, "0=scePowerRegisterCallback(%i, %i)", slot, cbId); if (slot < -1 || slot >= numberOfCBPowerSlotsPrivate) { return PSP_POWER_ERROR_INVALID_SLOT; } if (slot >= numberOfCBPowerSlots) { return PSP_POWER_ERROR_PRIVATE_SLOT; } // TODO: If cbId is invalid return PSP_POWER_ERROR_INVALID_CB. if (cbId == 0) { return PSP_POWER_ERROR_INVALID_CB; } int retval = -1; if (slot == POWER_CB_AUTO) { // -1 signifies auto select of bank for (int i=0; i < numberOfCBPowerSlots; i++) { if (powerCbSlots[i] == 0 && retval == -1) { // found an empty slot powerCbSlots[i] = cbId; retval = i; } } if (retval == -1) { return PSP_POWER_ERROR_SLOTS_FULL; } } else { if (powerCbSlots[slot] == 0) { powerCbSlots[slot] = cbId; retval = 0; } else { return PSP_POWER_ERROR_TAKEN_SLOT; } } if (retval >= 0) { __KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId); int arg = PSP_POWER_CB_AC_POWER | PSP_POWER_CB_BATTERY_EXIST | PSP_POWER_CB_BATTERY_FULL; __KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, arg); } return retval; }
int sceUmdActivate(u32 unknown, const char *name) { if (unknown < 1 || unknown > 2) return PSP_ERROR_UMD_INVALID_PARAM; bool changed = umdActivated == 0; __KernelUmdActivate(); 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 0; }
u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, int outLen) { if (strcmp(name, "emulator:")) { DEBUG_LOG(HLE,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd, argAddr, argLen, outPtr, outLen); } // UMD checks switch (cmd) { case 0x01F20001: // Get Disc Type. if (Memory::IsValidAddress(outPtr)) { Memory::Write_U32(0x10, outPtr); // Game disc return 0; } else { return -1; } break; case 0x01F20002: // Get current LBA. if (Memory::IsValidAddress(outPtr)) { Memory::Write_U32(0, outPtr); // Game disc return 0; } else { return -1; } break; case 0x01F100A3: // Seek return 0; } // This should really send it on to a FileSystem implementation instead. if (!strcmp(name, "mscmhc0:") || !strcmp(name, "ms0:")) { switch (cmd) { // does one of these set a callback as well? (see coded arms) case 0x02015804: // Register callback if (Memory::IsValidAddress(argAddr) && argLen == 4) { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId); __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State()); return 0; } else { return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } } break; case 0x02025805: // Unregister callback if (Memory::IsValidAddress(argAddr) && argLen == 4) { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick callback %i", cbId); return 0; } else { return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } } break; case 0x02025801: // Memstick Driver status? if (Memory::IsValidAddress(outPtr) && outLen >= 4) { Memory::Write_U32(4, outPtr); // JPSCP: The right return value is 4 for some reason return 0; } else { return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } case 0x02025806: // Memory stick inserted? if (Memory::IsValidAddress(outPtr) && outLen >= 4) { Memory::Write_U32(1, outPtr); return 0; } else { return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } case 0x02425818: // Get memstick size etc // Pretend we have a 2GB memory stick. if (Memory::IsValidAddress(argAddr) && argLen >= 4) { // "Should" be outPtr but isn't u32 pointer = Memory::Read_U32(argAddr); u32 sectorSize = 0x200; u32 memStickSectorSize = 32 * 1024; u32 sectorCount = memStickSectorSize / sectorSize; u64 freeSize = 1 * 1024 * 1024 * 1024; DeviceSize deviceSize; deviceSize.maxClusters = (u32)((freeSize * 95 / 100) / (sectorSize * sectorCount)); deviceSize.freeClusters = deviceSize.maxClusters; deviceSize.maxSectors = deviceSize.maxClusters; deviceSize.sectorSize = sectorSize; deviceSize.sectorCount = sectorCount; Memory::WriteStruct(pointer, &deviceSize); DEBUG_LOG(HLE, "Returned memstick size: maxSectors=%i", deviceSize.maxSectors); return 0; } else { ERROR_LOG(HLE, "memstick size query: bad params"); return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } } } if (!strcmp(name, "fatms0:")) { switch (cmd) { case 0x02415821: // MScmRegisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId); __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState()); return 0; } else { return -1; } } break; case 0x02415822: // MScmUnregisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); return 0; } else { return -1; } } case 0x02415823: // Set FAT as enabled if (Memory::IsValidAddress(argAddr) && argLen == 4) { MemoryStick_SetFatState((MemStickFatState)Memory::Read_U32(argAddr)); return 0; } else { ERROR_LOG(HLE, "Failed 0x02415823 fat"); return -1; } break; case 0x02425823: // Check if FAT enabled if (Memory::IsValidAddress(outPtr) && outLen == 4) { Memory::Write_U32(MemoryStick_FatState(), outPtr); return 0; } else { ERROR_LOG(HLE, "Failed 0x02425823 fat"); return -1; } break; case 0x02425818: // Get memstick size etc // Pretend we have a 2GB memory stick. { if (Memory::IsValidAddress(argAddr) && argLen >= 4) { // NOTE: not outPtr u32 pointer = Memory::Read_U32(argAddr); u32 sectorSize = 0x200; u32 memStickSectorSize = 32 * 1024; u32 sectorCount = memStickSectorSize / sectorSize; u64 freeSize = 1 * 1024 * 1024 * 1024; DeviceSize deviceSize; deviceSize.maxClusters = (u32)((freeSize * 95 / 100) / (sectorSize * sectorCount)); deviceSize.freeClusters = deviceSize.maxClusters; deviceSize.maxSectors = deviceSize.maxClusters; deviceSize.sectorSize = sectorSize; deviceSize.sectorCount = sectorCount; Memory::WriteStruct(pointer, &deviceSize); return 0; } else { return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS; } } } } if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:")) { // Emulator special tricks! switch (cmd) { case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests! return 0; case 2: // EMULATOR_DEVCTL__SEND_OUTPUT { std::string data(Memory::GetCharPointer(argAddr), argLen); if (PSP_CoreParameter().printfEmuLog) { host->SendDebugOutput(data.c_str()); } else { DEBUG_LOG(HLE, "%s", data.c_str()); } return 0; } case 3: // EMULATOR_DEVCTL__IS_EMULATOR if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); return 0; case 4: // EMULATOR_DEVCTL__VERIFY_STATE // Note that this is async, and makes sure the save state matches up. SaveState::Verify(); // TODO: Maybe save/load to a file just to be sure? return 0; } ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS"); return 0; } //089c6d1c weird branch /* 089c6bdc ]: HLE: sceKernelCreateCallback(name= MemoryStick Detection ,entry= 089c7484 ) (z_un_089c6bc4) 089c6c18 ]: HLE: sceIoDevctl("mscmhc0:", 02015804, 09ffb9c0, 4, 00000000, 0) (z_un_089c6bc4) 089c6c40 ]: HLE: sceKernelCreateCallback(name= MemoryStick Assignment ,entry= 089c7534 ) (z_un_089c6bc4) 089c6c78 ]: HLE: sceIoDevctl("fatms0:", 02415821, 09ffb9c4, 4, 00000000, 0) (z_un_089c6bc4) 089c6cac ]: HLE: sceIoDevctl("mscmhc0:", 02025806, 00000000, 0, 09ffb9c8, 4) (z_un_089c6bc4) */ return SCE_KERNEL_ERROR_UNSUP; }
void sceIoDevctl() //(const char *name, int cmd, void *arg, size_t arglen, void *buf, size_t *buflen); { const char *name = Memory::GetCharPointer(PARAM(0)); int cmd = PARAM(1); u32 argAddr = PARAM(2); int argLen = PARAM(3); u32 outPtr = PARAM(4); int outLen = PARAM(5); if (strcmp(name, "emulator:")) { DEBUG_LOG(HLE,"sceIoDevctl(\"%s\", %08x, %08x, %i, %08x, %i)", name, cmd,argAddr,argLen,outPtr,outLen); } // UMD checks switch (cmd) { case 0x01F20001: // Get Disc Type. if (Memory::IsValidAddress(outPtr)) { Memory::Write_U32(0x10, outPtr); // Game disc RETURN(0); return; } else { RETURN(-1); return; } break; case 0x01F20002: // Get current LBA. if (Memory::IsValidAddress(outPtr)) { Memory::Write_U32(0, outPtr); // Game disc RETURN(0); return; } else { RETURN(-1); return; } break; case 0x01F100A3: // Seek RETURN(0); return; break; } // This should really send it on to a FileSystem implementation instead. if (!strcmp(name, "mscmhc0:") || !strcmp(name, "ms0:")) { switch (cmd) { // does one of these set a callback as well? (see coded arms) case 0x02015804: // Register callback if (Memory::IsValidAddress(argAddr) && argLen == 4) { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId); __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State()); RETURN(0); } else { RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } return; } break; case 0x02025805: // Unregister callback if (Memory::IsValidAddress(argAddr) && argLen == 4) { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick callback %i", cbId); RETURN(0); } else { RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } return; } break; case 0x02025806: // Memory stick inserted? case 0x02025801: // Memstick Driver status? if (Memory::IsValidAddress(outPtr)) { Memory::Write_U32(1, outPtr); RETURN(0); } else { RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } return; case 0x02425818: // Get memstick size etc // Pretend we have a 2GB memory stick. if (Memory::IsValidAddress(argAddr)) { // "Should" be outPtr but isn't u32 pointer = Memory::Read_U32(argAddr); u64 totalSize = (u32)2 * 1024 * 1024 * 1024; u64 freeSize = 1 * 1024 * 1024 * 1024; DeviceSize deviceSize; deviceSize.maxSectors = 512; deviceSize.sectorSize = 0x200; deviceSize.sectorsPerCluster = 0x08; deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); deviceSize.freeClusters = (u32)((freeSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); Memory::WriteStruct(pointer, &deviceSize); RETURN(0); } else { RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } return; } } if (!strcmp(name, "fatms0:")) { switch (cmd) { case 0x02415821: // MScmRegisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId); __KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState()); RETURN(0); } else { RETURN(-1); } return; } break; case 0x02415822: // MScmUnregisterMSInsertEjectCallback { u32 cbId = Memory::Read_U32(argAddr); if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) { DEBUG_LOG(HLE, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId); RETURN(0); } else { RETURN(-1); } return; } case 0x02415823: // Set FAT as enabled if (Memory::IsValidAddress(argAddr) && argLen == 4) { MemoryStick_SetFatState((MemStickFatState)Memory::Read_U32(argAddr)); RETURN(0); } else { ERROR_LOG(HLE, "Failed 0x02415823 fat"); RETURN(-1); } break; case 0x02425823: // Check if FAT enabled if (Memory::IsValidAddress(outPtr) && outLen == 4) { Memory::Write_U32(MemoryStick_FatState(), outPtr); RETURN(0); } else { ERROR_LOG(HLE, "Failed 0x02425823 fat"); RETURN(-1); } break; case 0x02425818: // Get memstick size etc // Pretend we have a 2GB memory stick. { if (Memory::IsValidAddress(argAddr)) { // "Should" be outPtr but isn't u32 pointer = Memory::Read_U32(argAddr); u64 totalSize = (u32)2 * 1024 * 1024 * 1024; u64 freeSize = 1 * 1024 * 1024 * 1024; DeviceSize deviceSize; deviceSize.maxSectors = 512; deviceSize.sectorSize = 0x200; deviceSize.sectorsPerCluster = 0x08; deviceSize.totalClusters = (u32)((totalSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); deviceSize.freeClusters = (u32)((freeSize * 95 / 100) / (deviceSize.sectorSize * deviceSize.sectorsPerCluster)); Memory::WriteStruct(pointer, &deviceSize); RETURN(0); } else { RETURN(ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); } return; } } } if (!strcmp(name, "kemulator:") || !strcmp(name, "emulator:")) { // Emulator special tricks! switch (cmd) { case 1: // EMULATOR_DEVCTL__GET_HAS_DISPLAY if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(0, outPtr); // TODO: Make a headless mode for running tests! RETURN(0); return; case 2: // EMULATOR_DEVCTL__SEND_OUTPUT { std::string data(Memory::GetCharPointer(argAddr), argLen); if (PSP_CoreParameter().printfEmuLog) { printf("%s", data.c_str()); #ifdef _WIN32 OutputDebugString(data.c_str()); #endif // Also collect the debug output emuDebugOutput += data; } else { DEBUG_LOG(HLE, "%s", data.c_str()); } RETURN(0); return; } case 3: // EMULATOR_DEVCTL__IS_EMULATOR if (Memory::IsValidAddress(outPtr)) Memory::Write_U32(1, outPtr); // TODO: Make a headless mode for running tests! RETURN(0); return; } ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS"); RETURN(0); return; } //089c6d1c weird branch /* 089c6bdc ]: HLE: sceKernelCreateCallback(name= MemoryStick Detection ,entry= 089c7484 ) (z_un_089c6bc4) 089c6c18 ]: HLE: sceIoDevctl("mscmhc0:", 02015804, 09ffb9c0, 4, 00000000, 0) (z_un_089c6bc4) 089c6c40 ]: HLE: sceKernelCreateCallback(name= MemoryStick Assignment ,entry= 089c7534 ) (z_un_089c6bc4) 089c6c78 ]: HLE: sceIoDevctl("fatms0:", 02415821, 09ffb9c4, 4, 00000000, 0) (z_un_089c6bc4) 089c6cac ]: HLE: sceIoDevctl("mscmhc0:", 02025806, 00000000, 0, 09ffb9c8, 4) (z_un_089c6bc4) */ RETURN(SCE_KERNEL_ERROR_UNSUP); }