diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h index 7bae3179c5..ad5a9cfb32 100644 --- a/Utilities/StrUtil.h +++ b/Utilities/StrUtil.h @@ -186,4 +186,23 @@ namespace fmt const u8* buf; usz len; }; + + struct string_hash + { + using hash_type = std::hash; + 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); + } + }; } diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 457a789554..f45fbfaeb4 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -576,7 +576,7 @@ const std::array, 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 diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index ce2a9f1456..3ab168fed6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -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 diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 2c3cc14544..cee72c1d82 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -3,6 +3,7 @@ #include "Emu/Memory/vm_ptr.h" #include "Emu/Cell/ErrorCodes.h" #include "Utilities/File.h" +#include "Utilities/StrUtil.h" #include #include @@ -218,26 +219,7 @@ public: static bool vfs_unmount(std::string_view vpath); private: - struct string_hash - { - using hash_type = std::hash; - 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> map; + std::unordered_map> map; }; struct lv2_fs_object diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index 0d72d168f4..85bf8d1974 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -48,7 +48,6 @@ void fmt_class_string::format(std::string& out, u64 arg) struct UsbLdd { - std::string name; u16 id_vendor{}; u16 id_product_min{}; u16 id_product_max{}; @@ -86,8 +85,8 @@ public: void transfer_complete(libusb_transfer* transfer); // LDDs handling functions - u32 add_ldd(vm::ptr 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); @@ -131,7 +130,7 @@ private: u32 pipe_counter = 0x10; // Start at 0x10 only for tracing purposes // List of device drivers - std::vector ldds; + std::unordered_map> ldds; // List of pipes std::map open_pipes; @@ -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 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); + 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; - return ::size32(ldds); // TODO: to check + 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(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) @@ -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(dev->assigned_number), 0x02, 0x40}, dev)); - send_message(SYS_USBD_ATTACH, dev->assigned_number); - } - } - } -} - bool usb_handler_thread::get_event(vm::ptr& arg1, vm::ptr& arg2, vm::ptr& arg3) { if (!usbd_events.empty()) @@ -754,12 +771,11 @@ error_code sys_usbd_get_device_list(ppu_thread& ppu, u32 handle, vm::ptr 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 s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max) { 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_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>(); @@ -767,10 +783,32 @@ error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::ptr s_product, u16 slen_product) +{ + ppu.state += cpu_flag::wait; + + 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>(); + + 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.remove_ldd(product)) + return CELL_OK; + + return CELL_ESRCH; } error_code sys_usbd_get_descriptor_size(ppu_thread& ppu, u32 handle, u32 device_handle) @@ -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 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 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> 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) + {"guncon3", {0x0B9A, 0x0800, 0x0800}}, + {"PS3A-USJ", {0x0B9A, 0x0900, 0x0910}} + }; + + if (const auto iterator = predefined_ldds.find(product); iterator != predefined_ldds.end()) { - // 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 - { - 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 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 @@ -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)); diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.h b/rpcs3/Emu/Cell/lv2/sys_usbd.h index 0c2070b2b9..560e1a984b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.h +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.h @@ -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 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 descriptor, u32 desc_size); -error_code sys_usbd_register_ldd(ppu_thread& ppu, u32 handle, vm::ptr 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 s_product, u16 slen_product); +error_code sys_usbd_unregister_ldd(ppu_thread& ppu, u32 handle, vm::cptr 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); @@ -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 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 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 s_product, u16 slen_product);