From 61db5f945962a7c078a2fb1a565da1ea00527cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Oct 2026 15:48:41 +0200 Subject: [PATCH] VSH: Insert UMD Video discs, and report what kind of disc is in the drive A UMD Video image can now be inserted, and the drive's disc type (devctl 0x01F20001) comes from what's on the disc: PSP_GAME, UMD_VIDEO and UMD_AUDIO each set their bit. With a video disc the XMB moves to the Video column, shows the disc with its icon and background, and hands it to the firmware's video player when selected. sceUmdGetDiscInfo still tells games they're on a game disc. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceIo.cpp | 4 ++-- Core/HLE/sceUmd.cpp | 26 +++++++++++++++++++++++++- Core/HLE/sceUmd.h | 2 ++ Core/Loaders.cpp | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 2c34e5fecf..693021d959 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -1766,8 +1766,8 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o case 0x01F20001: // Get UMD disc type if (Memory::IsValid4AlignedRange(outPtr, 8) && outLen >= 8) { - // A game disc, or none in an empty drive (as JPCSP answers without a disc). - Memory::WriteUnchecked_U32(__UmdIsInserted() ? PSP_UMD_TYPE_GAME : 0, outPtr + 4); + // What's on the disc, or none in an empty drive (as JPCSP answers without a disc). + Memory::WriteUnchecked_U32(__UmdDiscType(), outPtr + 4); return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_ERROR_MEMSTICK_DEVCTL_BAD_PARAMS); diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 8da4ad0579..955c4c6dfb 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -287,7 +287,9 @@ static u32 sceUmdGetDiscInfo(u32 infoAddr) { if (info->size != 8) return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT); - info->type = PSP_UMD_TYPE_GAME; + // Games see a game disc, whatever else is on it. + const u32 type = __UmdDiscType(); + info->type = (type & PSP_UMD_TYPE_GAME) || type == 0 ? PSP_UMD_TYPE_GAME : type; return hleLogDebug(Log::sceIo, 0); } else { return hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT); @@ -546,6 +548,28 @@ bool __UmdIsInserted() { return UMDInserted; } +u32 __UmdDiscType() { + if (!UMDInserted) { + return 0; + } + auto hasDir = [](const char *path) { + const PSPFileInfo info = pspFileSystem.GetFileInfo(path); + return info.exists && info.type == FILETYPE_DIRECTORY; + }; + u32 type = 0; + if (hasDir("disc0:/PSP_GAME")) { + type |= PSP_UMD_TYPE_GAME; + } + if (hasDir("disc0:/UMD_VIDEO")) { + type |= PSP_UMD_TYPE_VIDEO; + } + if (hasDir("disc0:/UMD_AUDIO")) { + type |= PSP_UMD_TYPE_AUDIO; + } + // A loose game directory or an ISO without the usual layout still boots as a game. + return type != 0 ? type : PSP_UMD_TYPE_GAME; +} + bool getUMDReplacePermit() { return g_UMDReplacePermit; } diff --git a/Core/HLE/sceUmd.h b/Core/HLE/sceUmd.h index 165f7e3153..43681ec189 100644 --- a/Core/HLE/sceUmd.h +++ b/Core/HLE/sceUmd.h @@ -44,6 +44,8 @@ void __UmdReplace(const Path &filepath); bool __UmdInsert(const Path &filepath, std::string *error); void __UmdEject(); bool __UmdIsInserted(); +// What's on the disc in the drive (PSP_UMD_TYPE_* bits), or 0 for an empty drive. +u32 __UmdDiscType(); bool getUMDReplacePermit(); void Register_sceUmdUser(); diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 095dd3b321..72cc4620b7 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -376,6 +376,7 @@ bool UmdMount(const Path &filepath, FileLoader **fileLoader, std::string &error) case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: case IdentifiedFileType::PSP_DISC_DIRECTORY: + case IdentifiedFileType::PSP_UMD_VIDEO_ISO: if (!MountGameISO(loadedFile, &error)) { error = "mounting the ISO failed: " + error; return false;