Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapter hot-swapping support #257

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString&
const int tab_num)
: wxDialog(parent, wxID_ANY, name), m_pad_id(tab_num)
{
GCAdapter::ResetAdapterIfNecessary();

wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble"));
gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]);
gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this);
Expand Down
43 changes: 41 additions & 2 deletions Source/Core/InputCommon/GCAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static void ResetRumbleLockNeeded();
static void Reset();
static void Setup();

static bool s_detected = false;
static std::atomic<bool> s_detected = {false};
static libusb_device_handle* s_handle = nullptr;
static u8 s_controller_type[MAX_SI_CHANNELS] = {
ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE,
Expand Down Expand Up @@ -78,6 +78,10 @@ static u64 s_last_init = 0;
static u64 s_consecutive_slow_transfers = 0;
static double s_read_rate = 0.0;

static std::atomic<bool> external_thread_should_reset_polling_threads = {false};
static u64 s_consecutive_adapter_errors = 0;
static u64 s_consecutive_adapter_errors_limit = 100;

// Schmidtt trigger style, start applying if effective report rate > 290Hz, stop if < 260Hz
static const int stopApplyingEILVOptimsHz = 260;
static const int startApplyingEILVOptimsHz = 290;
Expand Down Expand Up @@ -341,13 +345,24 @@ const u8 *Fetch(std::chrono::high_resolution_clock::time_point *tp)
return controller_payload_entries.front().controller_payload;
}

void ResetAdapterIfNecessary()
{
if (external_thread_should_reset_polling_threads)
Reset();
}

bool IsReadingAtReducedRate()
{
return s_consecutive_slow_transfers > 80;
}

double ReadRate()
double ReadRate()
{
if (external_thread_should_reset_polling_threads)
{
Reset();
return 1e10;
}
return s_read_rate;
}

Expand All @@ -374,6 +389,20 @@ static void Read()

double elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start).count() / 1000000.0;

if (adapter_error && !external_thread_should_reset_polling_threads)
{
s_consecutive_adapter_errors++;
if (s_consecutive_adapter_errors >= s_consecutive_adapter_errors_limit)
{
s_consecutive_adapter_errors = 0;
external_thread_should_reset_polling_threads = true;
return;
}
}
else
{
s_consecutive_adapter_errors = 0;
}
// Store previous input and restore in the case of an adapter error
if (reuseOldInputsEnabled)
{
Expand Down Expand Up @@ -613,9 +642,11 @@ static bool CheckDeviceAccess(libusb_device* device)
}
// This call makes Nyko-brand (and perhaps other) adapters work.
// However it returns LIBUSB_ERROR_PIPE with Mayflash adapters.

const int transfer = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
if (transfer < 0)
WARN_LOG(SERIALINTERFACE, "libusb_control_transfer failed with error: %d", transfer);


// this split is needed so that we don't avoid claiming the interface when
// detaching the kernel driver is successful
Expand Down Expand Up @@ -728,6 +759,8 @@ static void Reset()
if (!s_detected)
return;

external_thread_should_reset_polling_threads = false;

if (s_adapter_thread_running.TestAndClear())
{
s_adapter_input_thread.join();
Expand Down Expand Up @@ -758,6 +791,12 @@ GCPadStatus Input(int chan, std::chrono::high_resolution_clock::time_point *tp)
if (s_handle == nullptr || !s_detected)
return{};

if (external_thread_should_reset_polling_threads)
{
Reset();
return{};
}

const SConfig &sconfig = SConfig::GetInstance();

#if defined(_WIN32)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/InputCommon/GCAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum ControllerTypes
CONTROLLER_WIRELESS = 2
};

void ResetAdapterIfNecessary();
bool IsReadingAtReducedRate();
double ReadRate();

Expand Down