sys_fs: Improved sys_fs_fcntl(0xc0000015&0xc000001c)

This commit is contained in:
brian218 2023-01-18 10:22:21 +08:00 committed by Megamouse
parent e0fe7989e9
commit d2dc57585c
10 changed files with 36 additions and 104 deletions

View file

@ -559,6 +559,18 @@ void cfg::log_entry::from_default()
set_map({});
}
std::pair<u16, u16> cfg::device_info::get_usb_ids() const
{
auto string_to_hex = [](const std::string& str) -> u16
{
u16 value = 0x0000;
if (!str.empty() && std::from_chars(str.data(), str.data() + str.size(), value, 16).ec != std::errc{})
cfg_log.error("Failed to parse hex from string \"%s\"", str);
return value;
};
return {string_to_hex(vid), string_to_hex(pid)};
}
void cfg::device_entry::set_map(map_of_type<device_info>&& map)
{
m_map = std::move(map);

View file

@ -644,6 +644,7 @@ namespace cfg
std::string serial;
std::string vid;
std::string pid;
std::pair<u16, u16> get_usb_ids() const;
};
class device_entry final : public _base

View file

@ -37,6 +37,12 @@ std::string utf16_to_utf8(std::u16string_view src)
return converter.to_bytes(src.data());
}
std::u16string utf8_to_utf16(std::string_view src)
{
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter{};
return converter.from_bytes(src.data());
}
std::wstring utf8_to_wchar(std::string_view src)
{
#ifdef _WIN32

View file

@ -11,6 +11,7 @@
std::wstring utf8_to_wchar(std::string_view src);
std::string wchar_to_utf8(std::wstring_view src);
std::string utf16_to_utf8(std::u16string_view src);
std::u16string utf8_to_utf16(std::string_view src);
// Copy null-terminated string from a std::string or a char array to a char array with truncation
template <typename D, typename T>

View file

@ -12,10 +12,8 @@
#include "Emu/IdManager.h"
#include "Emu/system_utils.hpp"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/RSX/Overlays/overlay_utils.h" // for ascii8_to_utf16
#include "Utilities/StrUtil.h"
#include <charconv>
#include <span>
LOG_CHANNEL(sys_fs);
@ -2117,33 +2115,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
}
const cfg::device_info device = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, vpath);
std::tie(arg->vendorID, arg->productID) = device.get_usb_ids();
if (device.path.empty() || device.vid.empty() || device.pid.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);
@ -2192,49 +2165,11 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
}
const cfg::device_info device = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, vpath);
if (device.path.empty() || device.vid.empty() || device.pid.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;
std::tie(arg->vendorID, arg->productID) = device.get_usb_ids();
// 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]);
}
const std::u16string serial = utf8_to_utf16(device.serial);
std::copy_n(serial.begin(), std::min(serial.size(), sizeof(arg->serial) / sizeof(u16)), arg->serial);
arg->out_code = CELL_OK;

View file

@ -533,7 +533,7 @@ struct lv2_file_c000001c : lv2_file_op
be_t<u16> vendorID;
be_t<u16> productID;
be_t<u32> out_code; // set to 0
u8 serial[64];
be_t<u16> serial[32];
};
CHECK_SIZE(lv2_file_c000001c, 0x60);

View file

@ -3,7 +3,6 @@
#include "sys_ppu_thread.h"
#include "sys_sync.h"
#include <charconv>
#include <queue>
#include "Emu/System.h"
#include "Emu/Memory/vm.h"
@ -295,30 +294,7 @@ usb_handler_thread::usb_handler_thread()
for (int i = 0; i < 8; i++) // Add VFS USB mass storage devices (/dev_usbXXX) to the USB device list
{
const cfg::device_info device = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/dev_usb%03d", i));
if (device.path.empty() || device.vid.empty() || device.pid.empty())
continue;
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());
}
}
usb_devices.push_back(std::make_shared<usb_device_vfs>(get_new_location(), vid, pid, device.serial));
usb_devices.push_back(std::make_shared<usb_device_vfs>(g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/dev_usb%03d", i)), get_new_location()));
}
if (!found_skylander)

View file

@ -1,8 +1,8 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/lv2/sys_usbd.h"
#include "Emu/Io/usb_device.h"
#include "Utilities/StrUtil.h"
#include <libusb.h>
LOG_CHANNEL(sys_usbd);
@ -244,13 +244,11 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size
}
else
{
const u8 len = std::min(strings[index - 1].size() * 2 + 2, static_cast<size_t>(0xFF));
const std::u16string u16str = utf8_to_utf16(strings[index - 1]);
const u8 len = std::min(u16str.size() * sizeof(u16) + 2, static_cast<size_t>(0xFF));
buf[0] = len;
expected_count = std::min(len, ::narrow<u8>(buf_size));
for (u32 i = 0; i < expected_count - 2; i++)
{
buf[i + 2] = i % 2 == 0 ? strings[index - 1].data()[i / 2] : 0;
}
memcpy(buf + 2, u16str.data(), expected_count - 2);
}
}
break;

View file

@ -3,9 +3,11 @@
LOG_CHANNEL(usb_vfs);
usb_device_vfs::usb_device_vfs(const std::array<u8, 7>& location, const u16 vid, const u16 pid, const std::string& serial)
usb_device_vfs::usb_device_vfs(const cfg::device_info& device_info, const std::array<u8, 7>& location)
: usb_device_emulated(location)
{
const auto [vid, pid] = device_info.get_usb_ids();
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE,
UsbDeviceDescriptor{
.bcdUSB = 0x0200,
@ -54,7 +56,7 @@ usb_device_vfs::usb_device_vfs(const std::array<u8, 7>& location, const u16 vid,
.wMaxPacketSize = 0x0200,
.bInterval = 0xFF}));
strings = {"SMI Corporation", "USB DISK", serial}; // Manufacturer, Product, SerialNumber
strings = {"SMI Corporation", "USB DISK", device_info.serial}; // Manufacturer, Product, SerialNumber
}
usb_device_vfs::~usb_device_vfs()

View file

@ -1,10 +1,11 @@
#pragma once
#include "Emu/Io/usb_device.h"
#include "Utilities/Config.h"
class usb_device_vfs : public usb_device_emulated
{
public:
usb_device_vfs(const std::array<u8, 7>& location, const u16 vid, const u16 pid, const std::string& serial);
usb_device_vfs(const cfg::device_info& device_info, const std::array<u8, 7>& location);
~usb_device_vfs();
};