USB: Added VFS USB mass storage devices to the USB device list

This commit is contained in:
brian218 2023-01-18 10:21:55 +08:00 committed by Megamouse
parent 709305df0e
commit e0fe7989e9
8 changed files with 213 additions and 26 deletions

View File

@ -389,6 +389,7 @@ target_sources(rpcs3_emu PRIVATE
Io/pad_config_types.cpp
Io/PadHandler.cpp
Io/usb_device.cpp
Io/usb_vfs.cpp
Io/Skylander.cpp
Io/GHLtar.cpp
Io/Buzz.cpp

View File

@ -3,15 +3,18 @@
#include "sys_ppu_thread.h"
#include "sys_sync.h"
#include <charconv>
#include <queue>
#include "Emu/System.h"
#include "Emu/Memory/vm.h"
#include "Emu/IdManager.h"
#include "Emu/vfs_config.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Io/usb_device.h"
#include "Emu/Io/usb_vfs.h"
#include "Emu/Io/Skylander.h"
#include "Emu/Io/GHLtar.h"
#include "Emu/Io/Buzz.h"
@ -290,6 +293,34 @@ usb_handler_thread::usb_handler_thread()
libusb_free_device_list(list, 1);
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));
}
if (!found_skylander)
{
sys_usbd.notice("Adding emulated skylander");

View File

@ -27,6 +27,12 @@ void usb_device::read_descriptors()
{
}
u32 usb_device::get_configuration(u8* buf)
{
*buf = current_config;
return sizeof(u8);
}
bool usb_device::set_configuration(u8 cfg_num)
{
current_config = cfg_num;
@ -123,6 +129,11 @@ void usb_device_passthrough::read_descriptors()
}
}
u32 usb_device_passthrough::get_configuration(u8* buf)
{
return (libusb_get_configuration(lusb_handle, reinterpret_cast<int*>(buf)) == LIBUSB_SUCCESS) ? sizeof(u8) : 0;
};
bool usb_device_passthrough::set_configuration(u8 cfg_num)
{
usb_device::set_configuration(cfg_num);
@ -187,32 +198,85 @@ bool usb_device_emulated::open_device()
return true;
}
s32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* ptr, u32 /*max_size*/)
u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size)
{
if (type == USB_DESCRIPTOR_STRING)
u32 expected_count = 2;
if (buf_size < expected_count)
{
if (index < strings.size())
{
u8 string_len = ::narrow<u8>(strings[index].size());
ptr[0] = (string_len * 2) + 2;
ptr[1] = USB_DESCRIPTOR_STRING;
for (u32 i = 0; i < string_len; i++)
{
ptr[2 + (i * 2)] = strings[index].data()[i];
ptr[3 + (i * 2)] = 0;
sys_usbd.error("Illegal buf_size: get_descriptor(type=0x%02x, index=0x%02x, buf=*0x%x, buf_size=0x%x)", type, index, buf, buf_size);
return 0;
}
return ptr[0];
buf[0] = expected_count;
buf[1] = type;
switch (type)
{
case USB_DESCRIPTOR_DEVICE:
{
buf[0] = device.bLength;
expected_count = std::min(device.bLength, ::narrow<u8>(buf_size));
memcpy(buf + 2, device.data, expected_count - 2);
break;
}
case USB_DESCRIPTOR_CONFIG:
{
if (index < device.subnodes.size())
{
buf[0] = device.subnodes[index].bLength;
expected_count = std::min(device.subnodes[index].bLength, ::narrow<u8>(buf_size));
memcpy(buf + 2, device.subnodes[index].data, expected_count - 2);
}
break;
}
case USB_DESCRIPTOR_STRING:
{
if (index < strings.size() + 1)
{
if (index == 0)
{
constexpr u8 len = sizeof(u16) + 2;
buf[0] = len;
expected_count = std::min(len, ::narrow<u8>(buf_size));
constexpr le_t<u16> langid = 0x0409; // English (United States)
memcpy(buf + 2, &langid, expected_count - 2);
}
else
{
sys_usbd.error("[Emulated]: Trying to get a descriptor other than string descriptor");
const u8 len = std::min(strings[index - 1].size() * 2 + 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;
}
}
}
break;
}
default: sys_usbd.error("Unhandled DescriptorType: get_descriptor(type=0x%02x, index=0x%02x, buf=*0x%x, buf_size=0x%x)", type, index, buf, buf_size); break;
}
return -1;
return expected_count;
}
void usb_device_emulated::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 /*wIndex*/, u16 /*wLength*/, u32 buf_size, u8* /*buf*/, UsbTransfer* transfer)
u32 usb_device_emulated::get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size)
{
constexpr u32 expected_count = sizeof(u16);
if (buf_size < expected_count)
{
sys_usbd.error("Illegal buf_size: get_status(self_powered=0x%02x, remote_wakeup=0x%02x, buf=*0x%x, buf_size=0x%x)", self_powered, remote_wakeup, buf, buf_size);
return 0;
}
const u16 device_status = self_powered | remote_wakeup << 1;
memcpy(buf, &device_status, expected_count);
return expected_count;
}
void usb_device_emulated::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 /*wIndex*/, u16 /*wLength*/, u32 buf_size, u8* buf, UsbTransfer* transfer)
{
transfer->fake = true;
transfer->expected_count = buf_size;
@ -221,15 +285,23 @@ void usb_device_emulated::control_transfer(u8 bmRequestType, u8 bRequest, u16 wV
switch (bmRequestType)
{
case 0:
case LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE:
switch (bRequest)
{
case 0x09: usb_device::set_configuration(::narrow<u8>(wValue)); break;
default: sys_usbd.fatal("Unhandled control transfer(0): 0x%x", bRequest); break;
case LIBUSB_REQUEST_SET_CONFIGURATION: usb_device::set_configuration(::narrow<u8>(wValue)); break;
default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break;
}
break;
case 0x80: sys_usbd.todo("Unimplemented control transfer: 0x%x", bmRequestType); break;
default: sys_usbd.fatal("Unhandled control transfer: 0x%x", bmRequestType); break;
case LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE:
switch (bRequest)
{
case LIBUSB_REQUEST_GET_STATUS: transfer->expected_count = get_status(false, false, buf, buf_size); break;
case LIBUSB_REQUEST_GET_DESCRIPTOR: transfer->expected_count = get_descriptor(wValue >> 8, wValue & 0xFF, buf, buf_size); break;
case LIBUSB_REQUEST_GET_CONFIGURATION: transfer->expected_count = get_configuration(buf); break;
default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break;
}
break;
default: sys_usbd.error("Unhandled control transfer: 0x%02x", bmRequestType); break;
}
}

View File

@ -177,6 +177,7 @@ public:
void get_location(u8* location) const;
virtual void read_descriptors();
virtual u32 get_configuration(u8* buf);
virtual bool set_configuration(u8 cfg_num);
virtual bool set_interface(u8 int_num);
@ -207,6 +208,7 @@ public:
bool open_device() override;
void read_descriptors() override;
u32 get_configuration(u8* buf) override;
bool set_configuration(u8 cfg_num) override;
bool set_interface(u8 int_num) override;
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
@ -234,7 +236,8 @@ public:
// Emulated specific functions
void add_string(char* str);
s32 get_descriptor(u8 type, u8 index, u8* ptr, u32 max_size);
u32 get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size);
u32 get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size);
protected:
std::vector<std::string> strings;

62
rpcs3/Emu/Io/usb_vfs.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "stdafx.h"
#include "usb_vfs.h"
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_emulated(location)
{
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE,
UsbDeviceDescriptor{
.bcdUSB = 0x0200,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 0x40,
.idVendor = vid,
.idProduct = pid,
.bcdDevice = pid,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01});
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG,
UsbDeviceConfiguration{
.wTotalLength = 0x0020,
.bNumInterfaces = 0x01,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = 0x80,
.bMaxPower = 0x32}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
UsbDeviceInterface{
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = 0x08,
.bInterfaceSubClass = 0x06,
.bInterfaceProtocol = 0x50,
.iInterface = 0x00}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
UsbDeviceEndpoint{
.bEndpointAddress = 0x81,
.bmAttributes = 0x02,
.wMaxPacketSize = 0x0200,
.bInterval = 0xFF}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
UsbDeviceEndpoint{
.bEndpointAddress = 0x02,
.bmAttributes = 0x02,
.wMaxPacketSize = 0x0200,
.bInterval = 0xFF}));
strings = {"SMI Corporation", "USB DISK", serial}; // Manufacturer, Product, SerialNumber
}
usb_device_vfs::~usb_device_vfs()
{
}

10
rpcs3/Emu/Io/usb_vfs.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "Emu/Io/usb_device.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();
};

View File

@ -370,6 +370,7 @@
<ClCompile Include="Emu\IdManager.cpp" />
<ClCompile Include="Emu\Io\Skylander.cpp" />
<ClCompile Include="Emu\Io\usb_device.cpp" />
<ClCompile Include="Emu\Io\usb_vfs.cpp" />
<ClCompile Include="Emu\RSX\Capture\rsx_capture.cpp" />
<ClCompile Include="Emu\RSX\Capture\rsx_replay.cpp" />
<ClCompile Include="Emu\RSX\Program\CgBinaryFragmentProgram.cpp" />
@ -641,6 +642,7 @@
<ClInclude Include="Emu\CPU\CPUTranslator.h" />
<ClInclude Include="Emu\Io\Skylander.h" />
<ClInclude Include="Emu\Io\usb_device.h" />
<ClInclude Include="Emu\Io\usb_vfs.h" />
<ClInclude Include="Emu\IPC.h" />
<ClInclude Include="Emu\Audio\AudioDumper.h" />
<ClInclude Include="Emu\Audio\AudioBackend.h" />

View File

@ -870,6 +870,9 @@
<ClCompile Include="Emu\Io\usb_device.cpp">
<Filter>Emu\Io</Filter>
</ClCompile>
<ClInclude Include="Emu\Io\usb_vfs.cpp">
<Filter>Emu\Io</Filter>
</ClCompile>
<ClCompile Include="util\atomic.cpp">
<Filter>Utilities</Filter>
</ClCompile>
@ -1851,6 +1854,9 @@
<ClInclude Include="Emu\Io\usb_device.h">
<Filter>Emu\Io</Filter>
</ClInclude>
<ClInclude Include="Emu\Io\usb_vfs.h">
<Filter>Emu\Io</Filter>
</ClCompile>
<ClInclude Include="Crypto\aesni.h">
<Filter>Crypto</Filter>
</ClInclude>