Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add device info to VFS #11968

Merged
merged 3 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions Utilities/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs)
out << YAML::EndMap;
return;
}
case type::device:
{
out << YAML::BeginMap;
for (const auto& [key, info] : static_cast<const device_entry&>(rhs).get_map())
{
out << YAML::Key << key;
out << YAML::BeginMap;
out << YAML::Key << "Path" << YAML::Value << info.path;
out << YAML::Key << "Serial" << YAML::Value << info.serial;
out << YAML::Key << "VID" << YAML::Value << info.vid;
out << YAML::Key << "PID" << YAML::Value << info.pid;
out << YAML::EndMap;
}
out << YAML::EndMap;
return;
}
default:
{
out << rhs.to_string();
Expand Down Expand Up @@ -355,6 +371,44 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic)
static_cast<log_entry&>(rhs).set_map(std::move(values));
break;
}
case type::device:
{
if (!data.IsMap())
{
return; // ???
}

map_of_type<device_info> values;

for (const auto& pair : data)
{
if (!pair.first.IsScalar() || !pair.second.IsMap()) continue;

device_info info{};

for (const auto& key_value : pair.second)
{
if (!key_value.first.IsScalar() || !key_value.second.IsScalar()) continue;

if (key_value.first.Scalar() == "Path")
info.path = key_value.second.Scalar();

if (key_value.first.Scalar() == "Serial")
info.serial = key_value.second.Scalar();

if (key_value.first.Scalar() == "VID")
info.vid = key_value.second.Scalar();

if (key_value.first.Scalar() == "PID")
info.pid = key_value.second.Scalar();
}

values.emplace(pair.first.Scalar(), std::move(info));
}

static_cast<device_entry&>(rhs).set_map(std::move(values));
break;
}
default:
{
std::string value;
Expand Down Expand Up @@ -456,3 +510,13 @@ void cfg::log_entry::from_default()
{
set_map({});
}

void cfg::device_entry::set_map(map_of_type<device_info>&& map)
{
m_map = std::move(map);
}

void cfg::device_entry::from_default()
{
m_map = m_default;
}
39 changes: 38 additions & 1 deletion Utilities/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ namespace cfg
string, // cfg::string type
set, // cfg::set_entry type
map, // cfg::map_entry type
log,
log, // cfg::log_entry type
device, // cfg::device_entry type
};

// Config tree entry abstract base class
Expand Down Expand Up @@ -521,4 +522,40 @@ namespace cfg

void from_default() override;
};

struct device_info
{
std::string path;
std::string serial;
std::string vid;
std::string pid;
};

class device_entry final : public _base
{
map_of_type<device_info> m_map{};
map_of_type<device_info> m_default{};

public:
device_entry(node* owner, const std::string& name, map_of_type<device_info> def = {})
: _base(type::device, owner, name, true)
, m_map(std::move(def))
{
m_default = m_map;
}

const map_of_type<device_info>& get_map() const
{
return m_map;
}

const map_of_type<device_info>& get_default() const
{
return m_default;
}

void set_map(map_of_type<device_info>&& map);

void from_default() override;
};
}
100 changes: 93 additions & 7 deletions rpcs3/Emu/Cell/lv2/sys_fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
#include "Crypto/unedat.h"
#include "Emu/System.h"
#include "Emu/VFS.h"
#include "Emu/vfs_config.h"
#include "Emu/IdManager.h"
#include "Emu/RSX/Overlays/overlay_utils.h" // for ascii8_to_utf16
#include "Utilities/StrUtil.h"

#include <charconv>

LOG_CHANNEL(sys_fs);

lv2_fs_mount_point g_mp_sys_dev_root;
Expand Down Expand Up @@ -1677,17 +1681,50 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
}

std::string_view vpath{ arg->name.get_ptr(), arg->name_size };

// Trim trailing '\0'
if (auto trim_pos = vpath.find('\0'); trim_pos != vpath.npos)
{
vpath.remove_suffix(vpath.size() - trim_pos);
}

if (!vpath.starts_with("/dev_usb"sv))
{
arg->out_code = CELL_ENOTSUP;
break;
}

// TODO hook up to config for dev_usb
// arg->vendorID = 0x0000;
// arg->productID = 0x0000;
const cfg::device_info device = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, vpath);

if (device.path.empty())
{
arg->out_code = CELL_ENOTSUP;
break;
}

u16 vid{};
{
auto [ptr, err] = std::from_chars(device.vid.data(), device.vid.data() + device.vid.size(), vid, 16);
if (err != std::errc())
{
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message());
}
}

u16 pid{};
{
auto [ptr, err] = std::from_chars(device.pid.data(), device.pid.data() + device.pid.size(), pid, 16);
if (err != std::errc())
{
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message());
}
}

arg->vendorID = vid;
arg->productID = pid;
arg->out_code = CELL_OK;

sys_fs.trace("sys_fs_fcntl(0xc0000015): found device '%s' (vid=0x%x, pid=0x%x)", vpath, arg->vendorID, arg->productID);
return CELL_OK;
}

Expand Down Expand Up @@ -1718,18 +1755,67 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
}

std::string_view vpath{ arg->name.get_ptr(), arg->name_size };

// Trim trailing '\0'
if (auto trim_pos = vpath.find('\0'); trim_pos != vpath.npos)
{
vpath.remove_suffix(vpath.size() - trim_pos);
}

if (!vpath.starts_with("/dev_usb"sv))
{
arg->out_code = CELL_ENOTSUP;
break;
}

// TODO hook up to config for dev_usb
// arg->vendorID = 0x0000;
// arg->productID = 0x0000;
// arg->serial = "blabla"; // String needs to be encoded to utf-16 BE
const cfg::device_info device = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, vpath);

if (device.path.empty())
{
arg->out_code = CELL_ENOTSUP;
break;
}

u16 vid{};
{
auto [ptr, err] = std::from_chars(device.vid.data(), device.vid.data() + device.vid.size(), vid, 16);
if (err != std::errc())
{
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message());
}
}

u16 pid{};
{
auto [ptr, err] = std::from_chars(device.pid.data(), device.pid.data() + device.pid.size(), pid, 16);
if (err != std::errc())
{
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message());
}
}

arg->vendorID = vid;
arg->productID = pid;

// Serial needs to be encoded to utf-16 BE
const std::u16string serial = ascii8_to_utf16(device.serial);
ensure((serial.size() * sizeof(u16)) <= sizeof(arg->serial));

std::memset(arg->serial, 0, sizeof(arg->serial));

const auto write_byteswapped = [](const void* src, void* dst) -> void
{
*static_cast<u16*>(dst) = *static_cast<const be_t<u16>*>(src);
};

for (size_t i = 0; i < serial.size(); i++)
{
write_byteswapped(&serial[i], &arg->serial[i * 2]);
}

arg->out_code = CELL_OK;

sys_fs.trace("sys_fs_fcntl(0xc000001c): found device '%s' (vid=0x%x, pid=0x%x, serial=%s)", vpath, arg->vendorID, arg->productID, device.serial);
return CELL_OK;
}

Expand Down
44 changes: 31 additions & 13 deletions rpcs3/Emu/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,40 @@ void Emulator::Init(bool add_only)
// Mount all devices
const std::string emu_dir = rpcs3::utils::get_emu_dir();
const std::string elf_dir = fs::get_parent_dir(m_path);
const std::string dev_hdd0 = g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, emu_dir);
const std::string dev_hdd1 = g_cfg_vfs.get(g_cfg_vfs.dev_hdd1, emu_dir);
const std::string dev_flsh = g_cfg_vfs.get_dev_flash();
const std::string dev_flsh2 = g_cfg_vfs.get_dev_flash2();
const std::string dev_flsh3 = g_cfg_vfs.get_dev_flash3();

vfs::mount("/dev_hdd0", g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, emu_dir));
vfs::mount("/dev_flash", g_cfg_vfs.get_dev_flash());
vfs::mount("/dev_flash2", g_cfg_vfs.get_dev_flash2());
vfs::mount("/dev_flash3", g_cfg_vfs.get_dev_flash3());
vfs::mount("/dev_usb", g_cfg_vfs.get(g_cfg_vfs.dev_usb000, emu_dir));
vfs::mount("/dev_usb000", g_cfg_vfs.get(g_cfg_vfs.dev_usb000, emu_dir));
vfs::mount("/dev_hdd0", dev_hdd0);
vfs::mount("/dev_flash", dev_flsh);
vfs::mount("/dev_flash2", dev_flsh2);
vfs::mount("/dev_flash3", dev_flsh3);
vfs::mount("/app_home", g_cfg_vfs.app_home.to_string().empty() ? elf_dir + '/' : g_cfg_vfs.get(g_cfg_vfs.app_home, emu_dir));

std::string dev_usb;

for (const auto& [key, value] : g_cfg_vfs.dev_usb.get_map())
{
const cfg::device_info usb_info = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, key, emu_dir);

if (key.size() != 11 || !key.starts_with("/dev_usb00"sv) || key.back() < '0' || key.back() > '7')
{
sys_log.error("Trying to mount unsupported usb device: %s", key);
continue;
}

vfs::mount(key, usb_info.path);

if (key == "/dev_usb000"sv)
{
dev_usb = usb_info.path;
}
}

ensure(!dev_usb.empty());

if (!hdd1.empty())
{
vfs::mount("/dev_hdd1", hdd1);
Expand Down Expand Up @@ -229,13 +254,6 @@ void Emulator::Init(bool add_only)
}

// Create directories (can be disabled if necessary)
const std::string dev_hdd0 = rpcs3::utils::get_hdd0_dir();
const std::string dev_hdd1 = g_cfg_vfs.get(g_cfg_vfs.dev_hdd1, emu_dir);
const std::string dev_usb = g_cfg_vfs.get(g_cfg_vfs.dev_usb000, emu_dir);
const std::string dev_flsh = g_cfg_vfs.get_dev_flash();
const std::string dev_flsh2 = g_cfg_vfs.get_dev_flash2();
const std::string dev_flsh3 = g_cfg_vfs.get_dev_flash3();

auto make_path_verbose = [](const std::string& path)
{
if (!fs::create_path(path))
Expand Down
37 changes: 35 additions & 2 deletions rpcs3/Emu/vfs_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ LOG_CHANNEL(vfs_log, "VFS");
cfg_vfs g_cfg_vfs{};

std::string cfg_vfs::get(const cfg::string& _cfg, std::string_view emu_dir) const
{
return get(_cfg.to_string(), _cfg.def, emu_dir);
}

std::string cfg_vfs::get(const std::string& _cfg, const std::string& def, std::string_view emu_dir) const
{
std::string _emu_dir; // Storage only

Expand All @@ -29,12 +34,12 @@ std::string cfg_vfs::get(const cfg::string& _cfg, std::string_view emu_dir) cons
emu_dir = _emu_dir;
}

std::string path = _cfg.to_string();
std::string path = _cfg;

if (path.empty())
{
// Fallback
path = _cfg.def;
path = def;
}

path = fmt::replace_all(path, "$(EmulatorDir)", emu_dir);
Expand All @@ -48,6 +53,34 @@ std::string cfg_vfs::get(const cfg::string& _cfg, std::string_view emu_dir) cons
return path;
}

cfg::device_info cfg_vfs::get_device(const cfg::device_entry& _cfg, std::string_view key, std::string_view emu_dir) const
{
return get_device_info(_cfg, key, emu_dir);
}

cfg::device_info cfg_vfs::get_device_info(const cfg::device_entry& _cfg, std::string_view key, std::string_view emu_dir) const
{
const auto& device_map = _cfg.get_map();

if (auto it = device_map.find(key); it != device_map.cend())
{
// Make sure the path is properly resolved
cfg::device_info info = it->second;
const auto& def_map = _cfg.get_default();
std::string def_path;

if (auto def_it = def_map.find(key); def_it != def_map.cend())
{
def_path = def_it->second.path;
}

info.path = get(info.path, def_path, emu_dir);
return info;
}

return {};
}

void cfg_vfs::load()
{
const std::string path = cfg_vfs::get_path();
Expand Down
Loading