diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index 5a845cbf3c..0d6eb7141a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -74,7 +74,6 @@ public: // Events related functions bool get_event(vm::ptr& arg1, vm::ptr& arg2, vm::ptr& arg3); void add_event(u64 arg1, u64 arg2, u64 arg3); - void add_to_receive_queue(ppu_thread* ppu); // Transfers related functions u32 get_free_transfer_id(); @@ -88,6 +87,9 @@ public: shared_mutex mutex; atomic_t is_init = false; + // sys_usbd_receive_event PPU Threads + std::deque sq; + static constexpr auto thread_name = "Usb Manager Thread"sv; private: @@ -108,9 +110,7 @@ private: std::array transfers; // Queue of pending usbd events - std::queue> usbd_events; - // sys_usbd_receive_event PPU Threads - std::queue receive_threads; + std::queue> usbd_events; // List of devices "connected" to the ps3 std::vector> usb_devices; @@ -389,9 +389,9 @@ bool usb_handler_thread::get_event(vm::ptr& arg1, vm::ptr& arg2, vm::p if (usbd_events.size()) { const auto& usb_event = usbd_events.front(); - *arg1 = (u64)std::get<0>(usb_event); - *arg2 = (u64)std::get<1>(usb_event); - *arg3 = (u64)std::get<2>(usb_event); + *arg1 = std::get<0>(usb_event); + *arg2 = std::get<1>(usb_event); + *arg3 = std::get<2>(usb_event); usbd_events.pop(); sys_usbd.trace("Received event: arg1=0x%x arg2=0x%x arg3=0x%x", *arg1, *arg2, *arg3); return true; @@ -402,18 +402,18 @@ bool usb_handler_thread::get_event(vm::ptr& arg1, vm::ptr& arg2, vm::p void usb_handler_thread::add_event(u64 arg1, u64 arg2, u64 arg3) { - usbd_events.push({arg1, arg2, arg3}); - if (receive_threads.size()) + // sys_usbd events use an internal event queue with SYS_SYNC_PRIORITY protocol + if (const auto cpu = lv2_obj::schedule(sq, SYS_SYNC_PRIORITY)) { - lv2_obj::awake(receive_threads.front()); - receive_threads.pop(); + cpu->gpr[4] = arg1; + cpu->gpr[5] = arg2; + cpu->gpr[6] = arg3; + lv2_obj::awake(cpu); + } + else + { + usbd_events.emplace(arg1, arg2, arg3); } -} - -void usb_handler_thread::add_to_receive_queue(ppu_thread* ppu) -{ - lv2_obj::sleep(*ppu); - receive_threads.push(ppu); } u32 usb_handler_thread::get_free_transfer_id() @@ -607,47 +607,43 @@ s32 sys_usbd_close_pipe(u32 handle, u32 pipe_handle) // *arg1 == 1 || *arg1 == 2 will send a sys_event to internal CellUsbd event queue with same parameters as received and loop(attach and detach event) s32 sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr arg1, vm::ptr arg2, vm::ptr arg3) { - lv2_obj::sleep(ppu); - sys_usbd.trace("sys_usbd_receive_event(handle=%u, arg1=*0x%x, arg2=*0x%x, arg3=*0x%x)", handle, arg1, arg2, arg3); const auto usbh = g_fxo->get>(); { std::lock_guard lock(usbh->mutex); + if (!usbh->is_init) return CELL_EINVAL; + + if (usbh->get_event(arg1, arg2, arg3)) + { + // hack for Guitar Hero Live + // Attaching the device too fast seems to result in a nullptr along the way + if (*arg1 == SYS_USBD_ATTACH) + lv2_obj::wait_timeout(5000); + + return CELL_OK; + } + + lv2_obj::sleep(ppu); + usbh->sq.emplace_back(&ppu); } - while (!Emu.IsStopped()) + while (!ppu.state.test_and_reset(cpu_flag::signal)) { + if (ppu.is_stopped()) { - std::lock_guard lock(usbh->mutex); - - if (usbh->get_event(arg1, arg2, arg3)) - { - // hack for Guitar Hero Live - // Attaching the device too fast seems to result in a nullptr along the way - if (*arg1 == SYS_USBD_ATTACH) - std::this_thread::sleep_for(5ms); - - break; - } - - usbh->add_to_receive_queue(&ppu); + return 0; } - while (!ppu.state.test_and_reset(cpu_flag::signal)) - { - if (ppu.is_stopped()) - { - return 0; - } - - thread_ctrl::wait(); - } + thread_ctrl::wait(); } + *arg1 = ppu.gpr[4]; + *arg2 = ppu.gpr[5]; + *arg3 = ppu.gpr[6]; return CELL_OK; }