summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorskidau <skidau@gmail.com>2015-05-01 12:09:18 +1000
committerskidau <skidau@gmail.com>2015-05-01 12:09:18 +1000
commit9348b2e1a661d7e430e70107569ec274e70a1c19 (patch)
tree98819d0e6a7b8d37d70cb2e7257eea7483e584c1 /Source
parent5cdac0d8269224777622e3cd2fd3e71d2d45c07a (diff)
parentec7445d66b81f75fd220889552b62d476a2d214c (diff)
Merge pull request #2330 from mathieui/background-gc-adapter-scan
Add a background thread to detect the GC adapter
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/ConfigManager.cpp2
-rw-r--r--Source/Core/Core/ConfigManager.h1
-rw-r--r--Source/Core/Core/HW/SI_GCAdapter.cpp244
-rw-r--r--Source/Core/Core/HW/SI_GCAdapter.h6
-rw-r--r--Source/Core/DolphinWX/ControllerConfigDiag.cpp55
-rw-r--r--Source/Core/DolphinWX/ControllerConfigDiag.h10
6 files changed, 222 insertions, 96 deletions
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index 89d561cfca..f23ca15730 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -354,6 +354,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("AdapterRumble", m_AdapterRumble);
}
void SConfig::SaveMovieSettings(IniFile& ini)
@@ -621,6 +622,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("AdapterRumble", &m_AdapterRumble, true);
}
void SConfig::LoadMovieSettings(IniFile& ini)
diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h
index 23fce73852..7a811e164a 100644
--- a/Source/Core/Core/ConfigManager.h
+++ b/Source/Core/Core/ConfigManager.h
@@ -116,6 +116,7 @@ struct SConfig : NonCopyable
// Input settings
bool m_BackgroundInput;
bool m_GameCubeAdapter;
+ bool m_AdapterRumble;
SysConf* m_SYSCONF;
diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp
index 13410ac592..9ec2f2ecf5 100644
--- a/Source/Core/Core/HW/SI_GCAdapter.cpp
+++ b/Source/Core/Core/HW/SI_GCAdapter.cpp
@@ -19,6 +19,9 @@ enum ControllerTypes
CONTROLLER_WIRELESS = 2
};
+static bool CheckDeviceAccess(libusb_device* device);
+static void AddGCAdapter(libusb_device* device);
+
static bool s_detected = false;
static libusb_device_handle* s_handle = nullptr;
static u8 s_controller_type[MAX_SI_CHANNELS] = { CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE };
@@ -33,8 +36,15 @@ static int s_controller_payload_size = 0;
static std::thread s_adapter_thread;
static Common::Flag s_adapter_thread_running;
+static std::thread s_adapter_detect_thread;
+static Common::Flag s_adapter_detect_thread_running;
+
+static std::function<void(void)> s_detect_callback;
+
static bool s_libusb_driver_not_supported = false;
static libusb_context* s_libusb_context = nullptr;
+static bool s_libusb_hotplug_enabled = false;
+static libusb_hotplug_callback_handle s_hotplug_handle;
static u8 s_endpoint_in = 0;
static u8 s_endpoint_out = 0;
@@ -56,6 +66,61 @@ static void Read()
}
}
+static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotplug_event event, void* user_data)
+{
+ if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
+ {
+ if (s_handle == nullptr && CheckDeviceAccess(dev))
+ AddGCAdapter(dev);
+ }
+ else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
+ {
+ if (s_handle != nullptr && libusb_get_device(s_handle) == dev)
+ Reset();
+ }
+ return 0;
+}
+
+static void ScanThreadFunc()
+{
+ Common::SetCurrentThreadName("GC Adapter Scanning Thread");
+ NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started");
+
+ s_libusb_hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0;
+ if (s_libusb_hotplug_enabled)
+ {
+ if (libusb_hotplug_register_callback(s_libusb_context, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, NULL, &s_hotplug_handle) != LIBUSB_SUCCESS)
+ s_libusb_hotplug_enabled = false;
+ if (s_libusb_hotplug_enabled)
+ NOTICE_LOG(SERIALINTERFACE, "Using libUSB hotplug detection");
+ }
+
+ while (s_adapter_detect_thread_running.IsSet())
+ {
+ if (s_libusb_hotplug_enabled)
+ {
+ static timeval tv = {0, 500000};
+ libusb_handle_events_timeout(s_libusb_context, &tv);
+ }
+ else
+ {
+ if (s_handle == nullptr)
+ {
+ Setup();
+ if (s_detected && s_detect_callback != nullptr)
+ s_detect_callback();
+ }
+ Common::SleepCurrentThread(500);
+ }
+ }
+ NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped");
+}
+
+void SetAdapterCallback(std::function<void(void)> func)
+{
+ s_detect_callback = func;
+}
+
void Init()
{
if (s_handle != nullptr)
@@ -80,13 +145,26 @@ void Init()
}
else
{
- Setup();
+ StartScanThread();
+ }
+}
+
+void StartScanThread()
+{
+ s_adapter_detect_thread_running.Set(true);
+ s_adapter_detect_thread = std::thread(ScanThreadFunc);
+}
+
+void StopScanThread()
+{
+ if (s_adapter_detect_thread_running.TestAndClear())
+ {
+ s_adapter_detect_thread.join();
}
}
void Setup()
{
- int ret;
libusb_device** list;
ssize_t cnt = libusb_get_device_list(s_libusb_context, &list);
@@ -96,87 +174,89 @@ void Setup()
s_controller_rumble[i] = 0;
}
-
for (int d = 0; d < cnt; d++)
{
libusb_device* device = list[d];
- libusb_device_descriptor desc;
- int dRet = libusb_get_device_descriptor(device, &desc);
- if (dRet)
- {
- // could not acquire the descriptor, no point in trying to use it.
- ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet);
- continue;
- }
+ if (CheckDeviceAccess(device))
+ AddGCAdapter(device);
+ }
- if (desc.idVendor == 0x057e && desc.idProduct == 0x0337)
- {
- NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, 1);
+ libusb_free_device_list(list, 1);
+}
+
+static bool CheckDeviceAccess(libusb_device* device)
+{
+ int ret;
+ libusb_device_descriptor desc;
+ int dRet = libusb_get_device_descriptor(device, &desc);
+ if (dRet)
+ {
+ // could not acquire the descriptor, no point in trying to use it.
+ ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet);
+ return false;
+ }
- u8 bus = libusb_get_bus_number(device);
- u8 port = libusb_get_device_address(device);
- ret = libusb_open(device, &s_handle);
- if (ret)
+ if (desc.idVendor == 0x057e && desc.idProduct == 0x0337)
+ {
+ NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, 1);
+
+ u8 bus = libusb_get_bus_number(device);
+ u8 port = libusb_get_device_address(device);
+ ret = libusb_open(device, &s_handle);
+ if (ret)
+ {
+ if (ret == LIBUSB_ERROR_ACCESS)
{
- if (ret == LIBUSB_ERROR_ACCESS)
+ if (dRet)
{
- if (dRet)
- {
- ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).",
- bus,
- port
- );
- }
- else
- {
- ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.",
- bus,
- port,
- desc.idVendor,
- desc.idProduct
- );
- }
+ ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).",
+ bus,
+ port
+ );
}
else
{
- ERROR_LOG(SERIALINTERFACE, "libusb_open failed to open device with error = %d", ret);
- if (ret == LIBUSB_ERROR_NOT_SUPPORTED)
- s_libusb_driver_not_supported = true;
+ ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.",
+ bus,
+ port,
+ desc.idVendor,
+ desc.idProduct
+ );
}
}
- else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1)
- {
- if ((ret = libusb_detach_kernel_driver(s_handle, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED)
- {
- ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret);
- }
- }
- // this split is needed so that we don't avoid claiming the interface when
- // detaching the kernel driver is successful
- if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
- {
- continue;
- }
- else if ((ret = libusb_claim_interface(s_handle, 0)))
+ else
{
- ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret);
+ ERROR_LOG(SERIALINTERFACE, "libusb_open failed to open device with error = %d", ret);
+ if (ret == LIBUSB_ERROR_NOT_SUPPORTED)
+ s_libusb_driver_not_supported = true;
}
- else
+ }
+ else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1)
+ {
+ if ((ret = libusb_detach_kernel_driver(s_handle, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED)
{
- AddGCAdapter(device);
- break;
+ ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret);
}
}
+ // this split is needed so that we don't avoid claiming the interface when
+ // detaching the kernel driver is successful
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
+ {
+ return false;
+ }
+ else if ((ret = libusb_claim_interface(s_handle, 0)))
+ {
+ ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret);
+ }
+ else
+ {
+ return true;
+ }
}
-
- libusb_free_device_list(list, 1);
-
- if (!s_detected)
- Shutdown();
+ return false;
}
-
-void AddGCAdapter(libusb_device* device)
+static void AddGCAdapter(libusb_device* device)
{
libusb_config_descriptor *config = nullptr;
libusb_get_config_descriptor(device, 0, &config);
@@ -205,10 +285,15 @@ void AddGCAdapter(libusb_device* device)
s_adapter_thread = std::thread(Read);
s_detected = true;
+ if (s_detect_callback != nullptr)
+ s_detect_callback();
}
void Shutdown()
{
+ StopScanThread();
+ if (s_libusb_hotplug_enabled)
+ libusb_hotplug_deregister_callback(s_libusb_context, s_hotplug_handle);
Reset();
if (s_libusb_context)
@@ -230,36 +315,29 @@ void Reset()
s_adapter_thread.join();
}
+ for (int i = 0; i < MAX_SI_CHANNELS; i++)
+ s_controller_type[i] = CONTROLLER_NONE;
+
+ s_detected = false;
+
if (s_handle)
{
libusb_release_interface(s_handle, 0);
libusb_close(s_handle);
s_handle = nullptr;
}
-
- for (int i = 0; i < MAX_SI_CHANNELS; i++)
- s_controller_type[i] = CONTROLLER_NONE;
+ if (s_detect_callback != nullptr)
+ s_detect_callback();
+ NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached");
}
-
void Input(int chan, GCPadStatus* pad)
{
if (!SConfig::GetInstance().m_GameCubeAdapter)
return;
- if (s_handle == nullptr)
- {
- if (s_detected)
- {
- Init();
- if (s_handle == nullptr)
- return;
- }
- else
- {
- return;
- }
- }
+ if (s_handle == nullptr || !s_detected)
+ return;
u8 controller_payload_copy[37];
@@ -271,7 +349,7 @@ void Input(int chan, GCPadStatus* pad)
if (s_controller_payload_size != sizeof(controller_payload_copy) || controller_payload_copy[0] != LIBUSB_DT_HID)
{
INFO_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", s_controller_payload_size, controller_payload_copy[0]);
- Shutdown();
+ Reset();
}
else
{
@@ -314,7 +392,7 @@ void Input(int chan, GCPadStatus* pad)
void Output(int chan, u8 rumble_command)
{
- if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
+ if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter || !SConfig::GetInstance().m_AdapterRumble)
return;
// Skip over rumble commands if it has not changed or the controller is wireless
@@ -330,7 +408,7 @@ void Output(int chan, u8 rumble_command)
if (size != 0x05 && size != 0x00)
{
INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size);
- Shutdown();
+ Reset();
}
}
}
diff --git a/Source/Core/Core/HW/SI_GCAdapter.h b/Source/Core/Core/HW/SI_GCAdapter.h
index 925e044b94..8c81e043c1 100644
--- a/Source/Core/Core/HW/SI_GCAdapter.h
+++ b/Source/Core/Core/HW/SI_GCAdapter.h
@@ -4,7 +4,7 @@
#pragma once
-struct libusb_device;
+#include <functional>
#include "Common/Thread.h"
#include "Core/HW/SI.h"
@@ -17,7 +17,9 @@ void Init();
void Reset();
void Setup();
void Shutdown();
-void AddGCAdapter(libusb_device* device);
+void SetAdapterCallback(std::function<void(void)> func);
+void StartScanThread();
+void StopScanThread();
void Input(int chan, GCPadStatus* pad);
void Output(int chan, u8 rumble_command);
bool IsDetected();
diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp
index 6f3ae906f5..df892e3eaa 100644
--- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp
+++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp
@@ -52,6 +52,8 @@ const std::array<wxString, 8> ControllerConfigDiag::m_gc_pad_type_strs = {{
_("AM-Baseboard")
}};
+wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent);
+
ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
: wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration"))
{
@@ -71,6 +73,7 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetSizerAndFit(main_sizer);
Center();
+ Bind(wxEVT_ADAPTER_UPDATE, &ControllerConfigDiag::UpdateAdapter, this);
}
wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
@@ -147,39 +150,64 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5);
gamecube_static_sizer->AddSpacer(5);
- wxStaticBoxSizer* const gamecube_adapter_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("GameCube Adapter"));
+ wxStaticBoxSizer* const gamecube_adapter_group = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Adapter"));
wxBoxSizer* const gamecube_adapter_sizer = new wxBoxSizer(wxHORIZONTAL);
wxCheckBox* const gamecube_adapter = new wxCheckBox(this, wxID_ANY, _("Direct Connect"));
gamecube_adapter->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnGameCubeAdapter, this);
+ wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble"));
+ gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble);
+ gamecube_rumble->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnAdapterRumble, this);
+
+ m_adapter_status = new wxStaticText(this, wxID_ANY, _("Adapter Not Detected"));
+
+ gamecube_adapter_group->Add(m_adapter_status, 0, wxEXPAND);
gamecube_adapter_sizer->Add(gamecube_adapter, 0, wxEXPAND);
+ gamecube_adapter_sizer->Add(gamecube_rumble, 0, wxEXPAND);
gamecube_adapter_group->Add(gamecube_adapter_sizer, 0, wxEXPAND);
gamecube_static_sizer->Add(gamecube_adapter_group, 0, wxEXPAND);
#if defined(__LIBUSB__) || defined (_WIN32)
+ gamecube_adapter->SetValue(SConfig::GetInstance().m_GameCubeAdapter);
if (!SI_GCAdapter::IsDetected())
{
if (!SI_GCAdapter::IsDriverDetected())
- gamecube_adapter->SetLabelText(_("Driver Not Detected"));
- else
- gamecube_adapter->SetLabelText(_("Adapter Not Detected"));
- gamecube_adapter->SetValue(false);
- gamecube_adapter->Disable();
- }
- else
- {
- gamecube_adapter->SetValue(SConfig::GetInstance().m_GameCubeAdapter);
- if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
+ m_adapter_status->SetLabelText(_("Driver Not Detected"));
gamecube_adapter->Disable();
+ gamecube_adapter->SetValue(false);
}
}
+ else
+ {
+ m_adapter_status->SetLabelText(_("Adapter Detected"));
+ }
+ if (Core::GetState() != Core::CORE_UNINITIALIZED)
+ {
+ gamecube_adapter->Disable();
+ }
+ SI_GCAdapter::SetAdapterCallback(std::bind(&ControllerConfigDiag::ScheduleAdapterUpdate, this));
#endif
return gamecube_static_sizer;
}
+void ControllerConfigDiag::ScheduleAdapterUpdate()
+{
+ wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE));
+}
+
+void ControllerConfigDiag::UpdateAdapter(wxCommandEvent& ev)
+{
+ bool unpause = Core::PauseAndLock(true);
+ if (SI_GCAdapter::IsDetected())
+ m_adapter_status->SetLabelText(_("Adapter Detected"));
+ else
+ m_adapter_status->SetLabelText(_("Adapter Not Detected"));
+ Core::PauseAndLock(false, unpause);
+}
+
wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
{
wxStaticText* wiimote_label[4];
@@ -537,3 +565,8 @@ void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event)
HotkeyManagerEmu::Enable(true);
}
+
+ControllerConfigDiag::~ControllerConfigDiag()
+{
+ SI_GCAdapter::SetAdapterCallback(nullptr);
+}
diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h
index 2f846d310e..c28c160f45 100644
--- a/Source/Core/DolphinWX/ControllerConfigDiag.h
+++ b/Source/Core/DolphinWX/ControllerConfigDiag.h
@@ -8,6 +8,7 @@
#include "Common/SysConf.h"
#include "Core/ConfigManager.h"
+#include "Core/HW/SI_GCAdapter.h"
#include "Core/HW/Wiimote.h"
class InputConfig;
@@ -19,6 +20,7 @@ class ControllerConfigDiag : public wxDialog
{
public:
ControllerConfigDiag(wxWindow* const parent);
+ ~ControllerConfigDiag();
private:
void RefreshRealWiimotes(wxCommandEvent& event);
@@ -72,6 +74,11 @@ private:
SConfig::GetInstance().m_GameCubeAdapter = event.IsChecked();
event.Skip();
}
+ void OnAdapterRumble(wxCommandEvent& event)
+ {
+ SConfig::GetInstance().m_AdapterRumble = event.IsChecked();
+ }
+
wxStaticBoxSizer* CreateGamecubeSizer();
wxStaticBoxSizer* CreateWiimoteConfigSizer();
@@ -82,6 +89,8 @@ private:
void Cancel(wxCommandEvent& event);
void OnGameCubePortChanged(wxCommandEvent& event);
void OnGameCubeConfigButton(wxCommandEvent& event);
+ void ScheduleAdapterUpdate();
+ void UpdateAdapter(wxCommandEvent& ev);
std::map<wxWindowID, unsigned int> m_gc_port_choice_ids;
std::map<wxWindowID, unsigned int> m_gc_port_config_ids;
@@ -90,6 +99,7 @@ private:
std::map<wxWindowID, unsigned int> m_wiimote_index_from_ctrl_id;
unsigned int m_orig_wiimote_sources[MAX_BBMOTES];
+ wxStaticText* m_adapter_status;
wxButton* wiimote_configure_bt[MAX_WIIMOTES];
wxButton* gamecube_configure_bt[4];
std::map<wxWindowID, unsigned int> m_wiimote_index_from_conf_bt_id;