Skip to content

Commit

Permalink
sys_usbd: Implemented sys_usbd_unregister_extra_ldd()
Browse files Browse the repository at this point in the history
  • Loading branch information
brian218 authored and kd-11 committed Jun 5, 2023
1 parent da0c9c2 commit c857759
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 94 deletions.
19 changes: 19 additions & 0 deletions Utilities/StrUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,23 @@ namespace fmt
const u8* buf;
usz len;
};

struct string_hash
{
using hash_type = std::hash<std::string_view>;
using is_transparent = void;

std::size_t operator()(const char* str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string_view str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string const& str) const
{
return hash_type{}(str);
}
};
}
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/lv2/lv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ const std::array<std::pair<ppu_intrp_func_t, std::string_view>, 1024> g_ppu_sysc
null_func,//BIND_SYSC(sys_usbd_...), //555 (0x22B)
BIND_SYSC(sys_usbd_get_device_speed), //556 (0x22C)
null_func,//BIND_SYSC(sys_usbd_...), //557 (0x22D)
null_func,//BIND_SYSC(sys_usbd_...), //558 (0x22E)
BIND_SYSC(sys_usbd_unregister_extra_ldd), //558 (0x22E)
BIND_SYSC(sys_usbd_register_extra_ldd), //559 (0x22F)
null_func,//BIND_SYSC(sys_...), //560 (0x230) ROOT
null_func,//BIND_SYSC(sys_...), //561 (0x231) ROOT
Expand Down
1 change: 0 additions & 1 deletion rpcs3/Emu/Cell/lv2/sys_fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "Emu/IdManager.h"
#include "Emu/system_utils.hpp"
#include "Emu/Cell/lv2/sys_process.h"
#include "Utilities/StrUtil.h"

#include <span>

Expand Down
22 changes: 2 additions & 20 deletions rpcs3/Emu/Cell/lv2/sys_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Utilities/File.h"
#include "Utilities/StrUtil.h"

#include <string>
#include <mutex>
Expand Down Expand Up @@ -218,26 +219,7 @@ struct lv2_fs_mount_info_map
static bool vfs_unmount(std::string_view vpath);

private:
struct string_hash
{
using hash_type = std::hash<std::string_view>;
using is_transparent = void;

std::size_t operator()(const char* str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string_view str) const
{
return hash_type{}(str);
}
std::size_t operator()(std::string const& str) const
{
return hash_type{}(str);
}
};

std::unordered_map<std::string, lv2_fs_mount_info, string_hash, std::equal_to<>> map;
std::unordered_map<std::string, lv2_fs_mount_info, fmt::string_hash, std::equal_to<>> map;
};

struct lv2_fs_object
Expand Down
178 changes: 109 additions & 69 deletions rpcs3/Emu/Cell/lv2/sys_usbd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ void fmt_class_string<libusb_transfer>::format(std::string& out, u64 arg)

struct UsbLdd
{
std::string name;
u16 id_vendor{};
u16 id_product_min{};
u16 id_product_max{};
Expand Down Expand Up @@ -86,8 +85,8 @@ class usb_handler_thread
void transfer_complete(libusb_transfer* transfer);

// LDDs handling functions
u32 add_ldd(vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max);
void check_devices_vs_ldds();
bool add_ldd(std::string_view product, u16 id_vendor, u16 id_product_min, u16 id_product_max);
bool remove_ldd(std::string_view product);

// Pipe functions
u32 open_pipe(u32 device_handle, u8 endpoint);
Expand Down Expand Up @@ -131,7 +130,7 @@ class usb_handler_thread
u32 pipe_counter = 0x10; // Start at 0x10 only for tracing purposes

// List of device drivers
std::vector<UsbLdd> ldds;
std::unordered_map<std::string, UsbLdd, fmt::string_hash, std::equal_to<>> ldds;

// List of pipes
std::map<u32, UsbPipe> open_pipes;
Expand Down Expand Up @@ -523,17 +522,64 @@ void usb_handler_thread::transfer_complete(struct libusb_transfer* transfer)
sys_usbd.trace("Transfer complete(0x%x): %s", usbd_transfer->transfer_id, *transfer);
}

u32 usb_handler_thread::add_ldd(vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
bool usb_handler_thread::add_ldd(std::string_view product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
{
UsbLdd new_ldd;
new_ldd.name.resize(slen_product);
memcpy(new_ldd.name.data(), s_product.get_ptr(), slen_product);
new_ldd.id_vendor = id_vendor;
new_ldd.id_product_min = id_product_min;
new_ldd.id_product_max = id_product_max;
ldds.push_back(new_ldd);

return ::size32(ldds); // TODO: to check
if (ldds.try_emplace(std::string(product), id_vendor, id_product_min, id_product_max).second)
{
for (const auto& dev : usb_devices)
{
if (dev->assigned_number)
continue;

if (dev->device._device.idVendor == id_vendor && dev->device._device.idProduct >= id_product_min && dev->device._device.idProduct <= id_product_max)
{
if (!dev->open_device())
{
sys_usbd.error("Failed to open device for LDD(VID:0x%04x PID:0x%04x)", dev->device._device.idVendor, dev->device._device.idProduct);
continue;
}

dev->read_descriptors();
dev->assigned_number = dev_counter++; // assign current dev_counter, and atomically increment

sys_usbd.notice("Ldd device matchup for <%s>, assigned as handled_device=0x%x", product, dev->assigned_number);

handled_devices.emplace(dev->assigned_number, std::pair(UsbInternalDevice{0x00, narrow<u8>(dev->assigned_number), 0x02, 0x40}, dev));
send_message(SYS_USBD_ATTACH, dev->assigned_number);
}
}

return true;
}

return false;
}

bool usb_handler_thread::remove_ldd(std::string_view product)
{
if (const auto iterator = ldds.find(product); iterator != ldds.end())
{
for (const auto& dev : usb_devices)
{
if (!dev->assigned_number)
continue;

if (dev->device._device.idVendor == iterator->second.id_vendor && dev->device._device.idProduct >= iterator->second.id_product_min && dev->device._device.idProduct <= iterator->second.id_product_max)
{
if (handled_devices.erase(dev->assigned_number))
{
sys_usbd.notice("Ldd device matchup for <%s>, removed 0x%x from handled_devices", iterator->first, dev->assigned_number);
send_message(SYS_USBD_DETACH, dev->assigned_number);
dev->assigned_number = 0;
}
}
}

ldds.erase(iterator);
return true;
}

return false;
}

u32 usb_handler_thread::open_pipe(u32 device_handle, u8 endpoint)
Expand All @@ -557,35 +603,6 @@ const UsbPipe& usb_handler_thread::get_pipe(u32 pipe_id) const
return ::at32(open_pipes, pipe_id);
}

void usb_handler_thread::check_devices_vs_ldds()
{
for (const auto& dev : usb_devices)
{
if (dev->assigned_number)
continue;

for (const auto& ldd : ldds)
{
if (dev->device._device.idVendor == ldd.id_vendor && dev->device._device.idProduct >= ldd.id_product_min && dev->device._device.idProduct <= ldd.id_product_max)
{
if (!dev->open_device())
{
sys_usbd.error("Failed to open device for LDD(VID:0x%04x PID:0x%04x)", dev->device._device.idVendor, dev->device._device.idProduct);
continue;
}

dev->read_descriptors();
dev->assigned_number = dev_counter++; // assign current dev_counter, and atomically increment

sys_usbd.success("Ldd device matchup for <%s>, assigned as handled_device=0x%x", ldd.name, dev->assigned_number);

handled_devices.emplace(dev->assigned_number, std::pair(UsbInternalDevice{0x00, narrow<u8>(dev->assigned_number), 0x02, 0x40}, dev));
send_message(SYS_USBD_ATTACH, dev->assigned_number);
}
}
}
}

bool usb_handler_thread::get_event(vm::ptr<u64>& arg1, vm::ptr<u64>& arg2, vm::ptr<u64>& arg3)
{
if (!usbd_events.empty())
Expand Down Expand Up @@ -754,23 +771,44 @@ error_code sys_usbd_get_device_list(ppu_thread& ppu, u32 handle, vm::ptr<UsbInte
return not_an_error(i_tocopy);
}

error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max)
{
ppu.state += cpu_flag::wait;

sys_usbd.trace("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d, id_vendor=0x%04x, id_product_min=0x%04x, id_product_max=0x%04x)", handle, s_product, slen_product, id_vendor, id_product_min, id_product_max);

auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();

std::lock_guard lock(usbh.mutex);
if (!usbh.is_init)
return CELL_EINVAL;

std::string_view product{s_product.get_ptr(), slen_product};

if (usbh.add_ldd(product, id_vendor, id_product_min, id_product_max))
return CELL_OK;

return CELL_EEXIST;
}

error_code sys_usbd_unregister_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product)
{
ppu.state += cpu_flag::wait;

sys_usbd.warning("sys_usbd_register_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d, id_vendor=0x%04x, id_product_min=0x%04x, id_product_max=0x%04x)", handle, s_product, slen_product, id_vendor,
id_product_min, id_product_max);
sys_usbd.trace("sys_usbd_unregister_extra_ldd(handle=0x%x, s_product=%s, slen_product=%d)", handle, s_product, slen_product);

auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();

std::lock_guard lock(usbh.mutex);
if (!usbh.is_init)
return CELL_EINVAL;

s32 res = usbh.add_ldd(s_product, slen_product, id_vendor, id_product_min, id_product_max);
usbh.check_devices_vs_ldds();
std::string_view product{s_product.get_ptr(), slen_product};

return not_an_error(res); // To check
if (usbh.remove_ldd(product))
return CELL_OK;

return CELL_ESRCH;
}

error_code sys_usbd_get_descriptor_size(ppu_thread& ppu, u32 handle, u32 device_handle)
Expand Down Expand Up @@ -812,37 +850,39 @@ error_code sys_usbd_get_descriptor(ppu_thread& ppu, u32 handle, u32 device_handl
return CELL_OK;
}

// This function is used for psp(cellUsbPspcm), dongles in ps3 arcade cabinets(PS3A-USJ), ps2 cam(eyetoy), generic usb camera?(sample_usb2cam)
error_code sys_usbd_register_ldd(ppu_thread& ppu, u32 handle, vm::ptr<char> s_product, u16 slen_product)
// This function is used for psp(cellUsbPspcm), ps3 arcade usj io(PS3A-USJ), ps2 cam(eyetoy), generic usb camera?(sample_usb2cam)
error_code sys_usbd_register_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product)
{
ppu.state += cpu_flag::wait;

std::string_view product{s_product.get_ptr(), slen_product};

// slightly hacky way of getting Namco GCon3 gun to work.
// The register_ldd appears to be a more promiscuous mode function, where all device 'inserts' would be presented to the cellUsbd for Probing.
// Unsure how many more devices might need similar treatment (i.e. just a compare and force VID/PID add), or if it's worth adding a full promiscuous
// capability
if (s_product.get_ptr() == "guncon3"sv)
// Unsure how many more devices might need similar treatment (i.e. just a compare and force VID/PID add), or if it's worth adding a full promiscuous capability
static const std::unordered_map<std::string, UsbLdd, fmt::string_hash, std::equal_to<>> predefined_ldds
{
sys_usbd.warning("sys_usbd_register_ldd(handle=0x%x, s_product=%s, slen_product=0x%x) -> Redirecting to sys_usbd_register_extra_ldd", handle, s_product, slen_product);
sys_usbd_register_extra_ldd(ppu, handle, s_product, slen_product, 0x0B9A, 0x0800, 0x0800);
}
else if (s_product.get_ptr() == "PS3A-USJ"sv)
{
// Arcade IO boards
sys_usbd.warning("sys_usbd_register_ldd(handle=0x%x, s_product=%s, slen_product=0x%x) -> Redirecting to sys_usbd_register_extra_ldd", handle, s_product, slen_product);
sys_usbd_register_extra_ldd(ppu, handle, s_product, slen_product, 0x0B9A, 0x0900, 0x0910);
}
else
{"guncon3", {0x0B9A, 0x0800, 0x0800}},
{"PS3A-USJ", {0x0B9A, 0x0900, 0x0910}}
};

if (const auto iterator = predefined_ldds.find(product); iterator != predefined_ldds.end())
{
sys_usbd.todo("sys_usbd_register_ldd(handle=0x%x, s_product=%s, slen_product=0x%x)", handle, s_product, slen_product);
sys_usbd.trace("sys_usbd_register_ldd(handle=0x%x, s_product=%s, slen_product=%d) -> Redirecting to sys_usbd_register_extra_ldd()", handle, s_product, slen_product);
return sys_usbd_register_extra_ldd(ppu, handle, s_product, slen_product, iterator->second.id_vendor, iterator->second.id_product_min, iterator->second.id_product_max);
}

sys_usbd.todo("sys_usbd_register_ldd(handle=0x%x, s_product=%s, slen_product=%d)", handle, s_product, slen_product);
return CELL_OK;
}

error_code sys_usbd_unregister_ldd(ppu_thread&)
error_code sys_usbd_unregister_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product)
{
sys_usbd.todo("sys_usbd_unregister_ldd()");
return CELL_OK;
ppu.state += cpu_flag::wait;

sys_usbd.trace("sys_usbd_unregister_ldd(handle=0x%x, s_product=%s, slen_product=%d) -> Redirecting to sys_usbd_unregister_extra_ldd()", handle, s_product, slen_product);

return sys_usbd_unregister_extra_ldd(ppu, handle, s_product, slen_product);
}

// TODO: determine what the unknown params are
Expand Down Expand Up @@ -999,7 +1039,7 @@ error_code sys_usbd_transfer_data(ppu_thread& ppu, u32 handle, u32 id_pipe, vm::

if (sys_usbd.trace && request)
{
sys_usbd.trace("RequestType:0x%x, Request:0x%x, wValue:0x%x, wIndex:0x%x, wLength:0x%x", request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength);
sys_usbd.trace("RequestType:0x%02x, Request:0x%02x, wValue:0x%04x, wIndex:0x%04x, wLength:0x%04x", request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength);

if ((request->bmRequestType & 0x80) == 0 && buf && buf_size != 0)
sys_usbd.trace("Control sent:\n%s", fmt::buf_to_hexstring(buf.get_ptr(), buf_size));
Expand Down
7 changes: 4 additions & 3 deletions rpcs3/Emu/Cell/lv2/sys_usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ error_code sys_usbd_finalize(ppu_thread& ppu, u32 handle);
error_code sys_usbd_get_device_list(ppu_thread& ppu, u32 handle, vm::ptr<UsbInternalDevice> device_list, u32 max_devices);
error_code sys_usbd_get_descriptor_size(ppu_thread& ppu, u32 handle, u32 device_handle);
error_code sys_usbd_get_descriptor(ppu_thread& ppu, u32 handle, u32 device_handle, vm::ptr<void> descriptor, u32 desc_size);
error_code sys_usbd_register_ldd(ppu_thread& ppu, u32 handle, vm::ptr<char> s_product, u16 slen_product);
error_code sys_usbd_unregister_ldd(ppu_thread& ppu);
error_code sys_usbd_register_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product);
error_code sys_usbd_unregister_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product);
error_code sys_usbd_open_pipe(ppu_thread& ppu, u32 handle, u32 device_handle, u32 unk1, u64 unk2, u64 unk3, u32 endpoint, u64 unk4);
error_code sys_usbd_open_default_pipe(ppu_thread& ppu, u32 handle, u32 device_handle);
error_code sys_usbd_close_pipe(ppu_thread& ppu, u32 handle, u32 pipe_handle);
Expand All @@ -84,4 +84,5 @@ error_code sys_usbd_event_port_send(ppu_thread& ppu, u32 handle, u64 arg1, u64 a
error_code sys_usbd_allocate_memory(ppu_thread& ppu);
error_code sys_usbd_free_memory(ppu_thread& ppu);
error_code sys_usbd_get_device_speed(ppu_thread& ppu);
error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::ptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max);
error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max);
error_code sys_usbd_unregister_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product);

0 comments on commit c857759

Please sign in to comment.