From 519970c0035badb0a11782e01c0b70e4f7c9aa09 Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 5 Jan 2015 12:43:26 +1100 Subject: [PATCH] Added a callback option instead of using a thread to read the GC adapter. --- Source/Core/Core/ConfigManager.cpp | 2 + Source/Core/Core/ConfigManager.h | 1 + Source/Core/Core/HW/SI_GCAdapter.cpp | 86 ++++++++++++++++--- .../Core/DolphinWX/ControllerConfigDiag.cpp | 10 +++ Source/Core/DolphinWX/ControllerConfigDiag.h | 5 ++ 5 files changed, 93 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index ff95320ca8..1c881d8d7a 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -343,6 +343,7 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend); core->Set("GPUDeterminismMode", m_LocalCoreStartupParameter.m_strGPUDeterminismMode); core->Set("GameCubeAdapter", m_GameCubeAdapter); + core->Set("GameCubeAdapterThread", m_GameCubeAdapterThread); } void SConfig::SaveMovieSettings(IniFile& ini) @@ -578,6 +579,7 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, ""); core->Get("GPUDeterminismMode", &m_LocalCoreStartupParameter.m_strGPUDeterminismMode, "auto"); core->Get("GameCubeAdapter", &m_GameCubeAdapter, true); + core->Get("GameCubeAdapterThread", &m_GameCubeAdapterThread, true); } void SConfig::LoadMovieSettings(IniFile& ini) diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index badf3fe04b..9d50ba028c 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -108,6 +108,7 @@ struct SConfig : NonCopyable // Input settings bool m_BackgroundInput; bool m_GameCubeAdapter; + bool m_GameCubeAdapterThread; SysConf* m_SYSCONF; diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp index 871d365265..655d76b068 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/Core/HW/SI_GCAdapter.cpp @@ -21,11 +21,15 @@ enum ControllerTypes static bool s_detected = false; static libusb_device_handle* s_handle = nullptr; +static libusb_transfer* s_irq_transfer_read = nullptr; +static libusb_transfer* s_irq_transfer_write = nullptr; static u8 s_controller_type[MAX_SI_CHANNELS] = { CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE }; static u8 s_controller_rumble[4]; static std::mutex s_mutex; static u8 s_controller_payload[37]; +static u8 s_controller_payload_swap[37]; + static int s_controller_payload_size = 0; static std::thread s_adapter_thread; @@ -39,17 +43,34 @@ static u8 s_endpoint_out = 0; static u64 s_last_init = 0; +#if defined(_WIN32) +#define LIBUSB_CALL WINAPI +#else +#define LIBUSB_CALL +#endif +extern "C" +{ + void LIBUSB_CALL read_callback(libusb_transfer* transfer); +} + +static void HandleEvents() +{ + while (s_adapter_thread_running.IsSet()) + { + libusb_handle_events(NULL); + Common::YieldCPU(); + } +} + static void Read() { while (s_adapter_thread_running.IsSet()) { - u8 controller_payload_swap[37]; - - libusb_interrupt_transfer(s_handle, s_endpoint_in, controller_payload_swap, sizeof(controller_payload_swap), &s_controller_payload_size, 0); + libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap, sizeof(s_controller_payload_swap), &s_controller_payload_size, 16); { std::lock_guard lk(s_mutex); - std::swap(controller_payload_swap, s_controller_payload); + std::swap(s_controller_payload_swap, s_controller_payload); } Common::YieldCPU(); @@ -177,10 +198,24 @@ void Init() int tmp = 0; unsigned char payload = 0x13; - libusb_interrupt_transfer(s_handle, s_endpoint_out, &payload, sizeof(payload), &tmp, 0); + libusb_interrupt_transfer(s_handle, s_endpoint_out, &payload, sizeof(payload), &tmp, 16); + + if (SConfig::GetInstance().m_GameCubeAdapterThread) + { + s_adapter_thread_running.Set(true); + s_adapter_thread = std::thread(Read); + } + else + { + s_irq_transfer_read = libusb_alloc_transfer(0); + s_irq_transfer_write = libusb_alloc_transfer(0); + libusb_fill_interrupt_transfer(s_irq_transfer_read, s_handle, s_endpoint_in, s_controller_payload_swap, sizeof(s_controller_payload_swap), read_callback, NULL, 16); + libusb_submit_transfer(s_irq_transfer_read); + + s_adapter_thread_running.Set(true); + s_adapter_thread = std::thread(HandleEvents); + } - s_adapter_thread_running.Set(true); - s_adapter_thread = std::thread(Read); s_detected = true; } } @@ -200,8 +235,16 @@ void Shutdown() s_adapter_thread.join(); } + if (!SConfig::GetInstance().m_GameCubeAdapterThread) + { + libusb_free_transfer(s_irq_transfer_read); + libusb_free_transfer(s_irq_transfer_write); + } + if (s_handle) { + libusb_release_interface(s_handle, 0); + libusb_reset_device(s_handle); libusb_close(s_handle); s_handle = nullptr; } @@ -293,12 +336,20 @@ void Output(int chan, u8 rumble_command) unsigned char rumble[5] = { 0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3] }; int size = 0; - libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 0); - if (size != 0x05) + if (SConfig::GetInstance().m_GameCubeAdapterThread) { - INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); - Shutdown(); + libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16); + if (size != 0x05) + { + INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); + Shutdown(); + } + } + else + { + libusb_fill_interrupt_transfer(s_irq_transfer_write, s_handle, s_endpoint_out, rumble, sizeof(rumble), NULL, &size, 16); + libusb_submit_transfer(s_irq_transfer_write); } } } @@ -313,4 +364,17 @@ bool IsDriverDetected() return !s_libusb_driver_not_supported; } +void LIBUSB_CALL read_callback(libusb_transfer *transfer) +{ + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + { + std::lock_guard lk(s_mutex); + s_controller_payload_size = transfer->actual_length; + memcpy(s_controller_payload, s_controller_payload_swap, s_controller_payload_size); + } + libusb_submit_transfer(s_irq_transfer_read); + } +} + } // end of namespace SI_GCAdapter diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index 94724a1c49..cb9c237373 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -146,7 +146,11 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() wxCheckBox* const gamecube_adapter = new wxCheckBox(this, wxID_ANY, _("Direct Connect")); gamecube_adapter->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnGameCubeAdapter, this); + wxCheckBox* const gamecube_adapter_thread = new wxCheckBox(this, wxID_ANY, _("Use Thread")); + gamecube_adapter_thread->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnGameCubeAdapterThread, this); + gamecube_adapter_sizer->Add(gamecube_adapter, 0, wxEXPAND); + gamecube_adapter_sizer->Add(gamecube_adapter_thread, 0, wxEXPAND); gamecube_adapter_group->Add(gamecube_adapter_sizer, 0, wxEXPAND); gamecube_static_sizer->Add(gamecube_adapter_group, 0, wxEXPAND); @@ -159,12 +163,18 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() gamecube_adapter->SetLabelText(_("Adapter Not Detected")); gamecube_adapter->SetValue(false); gamecube_adapter->Disable(); + gamecube_adapter_thread->SetValue(false); + gamecube_adapter_thread->Disable(); } else { gamecube_adapter->SetValue(SConfig::GetInstance().m_GameCubeAdapter); + gamecube_adapter_thread->SetValue(SConfig::GetInstance().m_GameCubeAdapterThread); if (Core::GetState() != Core::CORE_UNINITIALIZED) + { gamecube_adapter->Disable(); + gamecube_adapter_thread->Disable(); + } } #endif diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 1c5df13f4f..6fe5122b0e 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -64,6 +64,11 @@ public: SConfig::GetInstance().m_GameCubeAdapter = event.IsChecked(); event.Skip(); } + void OnGameCubeAdapterThread(wxCommandEvent& event) + { + SConfig::GetInstance().m_GameCubeAdapterThread = event.IsChecked(); + event.Skip(); + } private: wxStaticBoxSizer* CreateGamecubeSizer();