Merge branch 'swapdiscv2' of https://github.com/randprint/xenia into canary
[Kernel] XamSwapDisc and supporting functions swapdiscv2 (#1458)
This commit is contained in:
commit
07c9533c12
|
@ -43,6 +43,8 @@ using xe::ui::UIEvent;
|
||||||
|
|
||||||
const std::wstring kBaseTitle = L"xenia-canary";
|
const std::wstring kBaseTitle = L"xenia-canary";
|
||||||
|
|
||||||
|
ui::NativeWindowHandle window_handle;
|
||||||
|
|
||||||
EmulatorWindow::EmulatorWindow(Emulator* emulator)
|
EmulatorWindow::EmulatorWindow(Emulator* emulator)
|
||||||
: emulator_(emulator),
|
: emulator_(emulator),
|
||||||
loop_(ui::Loop::Create()),
|
loop_(ui::Loop::Create()),
|
||||||
|
@ -326,6 +328,7 @@ void EmulatorWindow::FileOpen() {
|
||||||
{L"All Files (*.*)", L"*.*"},
|
{L"All Files (*.*)", L"*.*"},
|
||||||
});
|
});
|
||||||
if (file_picker->Show(window_->native_handle())) {
|
if (file_picker->Show(window_->native_handle())) {
|
||||||
|
window_handle = window_->native_handle();
|
||||||
auto selected_files = file_picker->selected_files();
|
auto selected_files = file_picker->selected_files();
|
||||||
if (!selected_files.empty()) {
|
if (!selected_files.empty()) {
|
||||||
path = selected_files[0];
|
path = selected_files[0];
|
||||||
|
@ -344,6 +347,30 @@ void EmulatorWindow::FileOpen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring EmulatorWindow::SwapNext() {
|
||||||
|
std::wstring path = L"";
|
||||||
|
|
||||||
|
auto file_picker = xe::ui::FilePicker::Create();
|
||||||
|
file_picker->set_mode(ui::FilePicker::Mode::kOpen);
|
||||||
|
file_picker->set_type(ui::FilePicker::Type::kFile);
|
||||||
|
file_picker->set_multi_selection(false);
|
||||||
|
file_picker->set_title(L"Select Content Package");
|
||||||
|
file_picker->set_extensions({
|
||||||
|
{L"Supported Files", L"*.iso;*.xex;*.xcp;*.*"},
|
||||||
|
{L"Disc Image (*.iso)", L"*.iso"},
|
||||||
|
{L"Xbox Executable (*.xex)", L"*.xex"},
|
||||||
|
// { L"Content Package (*.xcp)", L"*.xcp" },
|
||||||
|
{L"All Files (*.*)", L"*.*"},
|
||||||
|
});
|
||||||
|
if (file_picker->Show(window_handle)) {
|
||||||
|
auto selected_files = file_picker->selected_files();
|
||||||
|
if (!selected_files.empty()) {
|
||||||
|
path = selected_files[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatorWindow::FileClose() {
|
void EmulatorWindow::FileClose() {
|
||||||
if (emulator_->is_title_open()) {
|
if (emulator_->is_title_open()) {
|
||||||
emulator_->TerminateTitle();
|
emulator_->TerminateTitle();
|
||||||
|
|
|
@ -37,6 +37,7 @@ class EmulatorWindow {
|
||||||
|
|
||||||
void UpdateTitle();
|
void UpdateTitle();
|
||||||
void ToggleFullscreen();
|
void ToggleFullscreen();
|
||||||
|
static std::wstring SwapNext();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit EmulatorWindow(Emulator* emulator);
|
explicit EmulatorWindow(Emulator* emulator);
|
||||||
|
|
|
@ -7,11 +7,20 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "xenia/app/emulator_window.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
|
#include "xenia/kernel/xam/xam_module.h"
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
|
||||||
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||||
#include "xenia/kernel/xenumerator.h"
|
#include "xenia/kernel/xenumerator.h"
|
||||||
|
#include "xenia/kernel/xevent.h"
|
||||||
|
#include "xenia/kernel/xthread.h"
|
||||||
|
#include "xenia/vfs/devices/disc_image_device.h"
|
||||||
|
#include "xenia/vfs/devices/host_path_device.h"
|
||||||
|
#include "xenia/vfs/devices/stfs_container_device.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
DEFINE_int32(license_mask, 0,
|
DEFINE_int32(license_mask, 0,
|
||||||
|
@ -474,6 +483,74 @@ dword_result_t XamContentDelete(dword_t user_index, lpvoid_t content_data_ptr,
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamContentDelete, kContent, kImplemented);
|
DECLARE_XAM_EXPORT1(XamContentDelete, kContent, kImplemented);
|
||||||
|
|
||||||
|
// Based on Discswap Prototype from Wildenhaus
|
||||||
|
// https://github.com/Wildenhaus/xenia/commit/04d2e3951c13fbe4f9574005122d757a2f6e373c
|
||||||
|
dword_result_t XamSwapDisc(dword_t disc_number,
|
||||||
|
pointer_t<kernel::X_KEVENT> completion_handle,
|
||||||
|
lpstring_t error_message) {
|
||||||
|
auto filesystem = kernel_state()->file_system();
|
||||||
|
auto mount_path = "\\Device\\LauncherData";
|
||||||
|
|
||||||
|
if (filesystem->ResolveDevice(mount_path) != NULL) {
|
||||||
|
filesystem->UnregisterDevice(mount_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error_message not correct type/ptr
|
||||||
|
XELOGI("XamSwapDisc requests disc %d.", disc_number);
|
||||||
|
std::wstring local_path = app::EmulatorWindow::SwapNext();
|
||||||
|
XELOGI("SwapNext returned path %S.", local_path.c_str());
|
||||||
|
|
||||||
|
auto last_slash = local_path.find_last_of(xe::kPathSeparator);
|
||||||
|
auto last_dot = local_path.find_last_of('.');
|
||||||
|
|
||||||
|
if (last_dot < last_slash) {
|
||||||
|
last_dot = std::wstring::npos;
|
||||||
|
}
|
||||||
|
if (last_dot == std::wstring::npos) {
|
||||||
|
// Likely an STFS container.
|
||||||
|
auto dev =
|
||||||
|
std::make_unique<vfs::StfsContainerDevice>(mount_path, local_path);
|
||||||
|
dev->Initialize();
|
||||||
|
filesystem->RegisterDevice(std::move(dev));
|
||||||
|
};
|
||||||
|
auto extension = local_path.substr(last_dot);
|
||||||
|
std::transform(extension.begin(), extension.end(), extension.begin(),
|
||||||
|
tolower);
|
||||||
|
if (extension == L".xex" || extension == L".elf" || extension == L".exe") {
|
||||||
|
// Treat as a naked xex file.
|
||||||
|
auto parent_path = xe::find_base_path(local_path);
|
||||||
|
auto dev =
|
||||||
|
std::make_unique<vfs::HostPathDevice>(mount_path, parent_path, true);
|
||||||
|
dev->Initialize();
|
||||||
|
filesystem->RegisterDevice(std::move(dev));
|
||||||
|
} else {
|
||||||
|
// Assume a disc image.
|
||||||
|
auto dev = std::make_unique<vfs::DiscImageDevice>(mount_path, local_path);
|
||||||
|
dev->Initialize();
|
||||||
|
filesystem->RegisterDevice(std::move(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the new device to d: and game:
|
||||||
|
filesystem->UnregisterSymbolicLink("d:");
|
||||||
|
filesystem->UnregisterSymbolicLink("game:");
|
||||||
|
filesystem->RegisterSymbolicLink("d:", mount_path);
|
||||||
|
filesystem->RegisterSymbolicLink("game:", mount_path);
|
||||||
|
|
||||||
|
// Resolve the pending disc swap event
|
||||||
|
auto kevent = xboxkrnl::xeKeSetEvent(completion_handle, 1, 0);
|
||||||
|
|
||||||
|
// Release the completion handle
|
||||||
|
auto object = XObject::GetNativeObject<XObject>(
|
||||||
|
kernel_state(),
|
||||||
|
kernel_memory()->virtual_membase() + (dword_t)completion_handle);
|
||||||
|
if (object) {
|
||||||
|
object->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT1(XamSwapDisc, kContent, kSketchy);
|
||||||
|
|
||||||
void RegisterContentExports(xe::cpu::ExportResolver* export_resolver,
|
void RegisterContentExports(xe::cpu::ExportResolver* export_resolver,
|
||||||
KernelState* kernel_state) {}
|
KernelState* kernel_state) {}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,26 @@ VirtualFileSystem::~VirtualFileSystem() {
|
||||||
devices_.clear();
|
devices_.clear();
|
||||||
symlinks_.clear();
|
symlinks_.clear();
|
||||||
}
|
}
|
||||||
|
Entry* VirtualFileSystem::ResolveDevice(const std::string& devicepath) {
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
|
// Resolve relative paths
|
||||||
|
std::string normalized_path(xe::filesystem::CanonicalizePath(devicepath));
|
||||||
|
|
||||||
|
// Find the device.
|
||||||
|
auto it =
|
||||||
|
std::find_if(devices_.cbegin(), devices_.cend(), [&](const auto& d) {
|
||||||
|
return xe::find_first_of_case(normalized_path, d->mount_path()) == 0;
|
||||||
|
});
|
||||||
|
if (it == devices_.cend()) {
|
||||||
|
XELOGE("ResolveDevice(%s) device not initialized", devicepath.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& device = *it;
|
||||||
|
auto relative_path = normalized_path.substr(device->mount_path().size());
|
||||||
|
return device->ResolvePath(relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
|
bool VirtualFileSystem::RegisterDevice(std::unique_ptr<Device> device) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
|
@ -27,6 +27,7 @@ class VirtualFileSystem {
|
||||||
public:
|
public:
|
||||||
VirtualFileSystem();
|
VirtualFileSystem();
|
||||||
~VirtualFileSystem();
|
~VirtualFileSystem();
|
||||||
|
Entry* ResolveDevice(const std::string& path);
|
||||||
|
|
||||||
bool RegisterDevice(std::unique_ptr<Device> device);
|
bool RegisterDevice(std::unique_ptr<Device> device);
|
||||||
bool UnregisterDevice(const std::string& path);
|
bool UnregisterDevice(const std::string& path);
|
||||||
|
|
Loading…
Reference in New Issue