GCAdapter: Report libusb open errors to the user

If opening the adapter fails, report the libusb error message in the GUI
instead of “No Adapter Detected”.

The error condition is removed when the adapter is unplugged.
This commit is contained in:
Vincent Duvert 2018-07-17 22:31:18 +02:00
parent 0165e5e703
commit b08e2ec959
4 changed files with 60 additions and 24 deletions

View File

@ -391,9 +391,9 @@ void DolphinAnalytics::MakePerGameBuilder()
// We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind
// of gamepad
// or the official gamecube adapter.
builder.AddData("gcadapter-detected", GCAdapter::IsDetected());
builder.AddData("gcadapter-detected", GCAdapter::IsDetected(nullptr));
builder.AddData("has-controller", Pad::GetConfig()->IsControllerControlledByGamepadDevice(0) ||
GCAdapter::IsDetected());
GCAdapter::IsDetected(nullptr));
m_per_game_builder = builder;
}

View File

@ -28,9 +28,25 @@ void GCPadWiiUConfigDialog::CreateLayout()
{
setWindowTitle(tr("GameCube Adapter for Wii U at Port %1").arg(m_port + 1));
const bool detected = GCAdapter::IsDetected();
const char* error_message = nullptr;
const bool detected = GCAdapter::IsDetected(&error_message);
QString status_text;
if (detected)
{
status_text = tr("Adapter Detected");
}
else if (error_message)
{
status_text = tr("Error Opening Adapter: %1").arg(QString::fromUtf8(error_message));
}
else
{
status_text = tr("No Adapter Detected");
}
m_layout = new QVBoxLayout();
m_status_label = new QLabel(detected ? tr("Adapter Detected") : tr("No Adapter Detected"));
m_status_label = new QLabel(status_text);
m_rumble = new QCheckBox(tr("Enable Rumble"));
m_simulate_bongos = new QCheckBox(tr("Simulate DK Bongos"));
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok);

View File

@ -9,6 +9,7 @@
#include "Common/Event.h"
#include "Common/Flag.h"
#include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
@ -29,7 +30,14 @@ static void ResetRumbleLockNeeded();
static void Reset();
static void Setup();
static bool s_detected = false;
enum
{
NO_ADAPTER_DETECTED = 0,
ADAPTER_DETECTED = 1,
};
// Current adapter status: detected/not detected/in error (holds the error code)
static int s_status = NO_ADAPTER_DETECTED;
static libusb_device_handle* s_handle = nullptr;
static u8 s_controller_type[SerialInterface::MAX_SI_CHANNELS] = {
ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE,
@ -54,7 +62,6 @@ static Common::Flag s_adapter_detect_thread_running;
static std::function<void(void)> s_detect_callback;
static bool s_libusb_driver_not_supported = false;
#if defined(__FreeBSD__) && __FreeBSD__ >= 11
static bool s_libusb_hotplug_enabled = true;
#else
@ -120,6 +127,10 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl
{
if (s_handle != nullptr && libusb_get_device(s_handle) == dev)
Reset();
// Reset a potential error status now that the adapter is unplugged
if (s_status < 0)
s_status = 0;
}
return 0;
}
@ -158,7 +169,7 @@ static void ScanThreadFunc()
{
std::lock_guard<std::mutex> lk(s_init_mutex);
Setup();
if (s_detected && s_detect_callback != nullptr)
if (s_status == ADAPTER_DETECTED && s_detect_callback != nullptr)
s_detect_callback();
}
Common::SleepCurrentThread(500);
@ -184,7 +195,7 @@ void Init()
s_last_init = CoreTiming::GetTicks();
}
s_libusb_driver_not_supported = false;
s_status = NO_ADAPTER_DETECTED;
if (UseAdapter())
StartScanThread();
@ -247,6 +258,9 @@ static bool CheckDeviceAccess(libusb_device* device)
NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d",
desc.idVendor, desc.idProduct, 1);
// In case of failure, capture the libusb error code into the adapter status
Common::ScopeGuard status_guard([&ret] { s_status = ret; });
u8 bus = libusb_get_bus_number(device);
u8 port = libusb_get_device_address(device);
ret = libusb_open(device, &s_handle);
@ -260,8 +274,6 @@ static bool CheckDeviceAccess(libusb_device* device)
if (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;
return false;
}
@ -291,6 +303,9 @@ static bool CheckDeviceAccess(libusb_device* device)
return false;
}
// Updating the adapter status will be done in AddGCAdapter
status_guard.Dismiss();
return true;
}
@ -323,7 +338,7 @@ static void AddGCAdapter(libusb_device* device)
s_adapter_input_thread = std::thread(Read);
s_adapter_output_thread = std::thread(Write);
s_detected = true;
s_status = ADAPTER_DETECTED;
if (s_detect_callback != nullptr)
s_detect_callback();
ResetRumbleLockNeeded();
@ -338,7 +353,7 @@ void Shutdown()
#endif
Reset();
s_libusb_driver_not_supported = false;
s_status = NO_ADAPTER_DETECTED;
}
static void Reset()
@ -346,7 +361,7 @@ static void Reset()
std::unique_lock<std::mutex> lock(s_init_mutex, std::defer_lock);
if (!lock.try_lock())
return;
if (!s_detected)
if (s_status != ADAPTER_DETECTED)
return;
if (s_adapter_thread_running.TestAndClear())
@ -359,7 +374,7 @@ static void Reset()
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; i++)
s_controller_type[i] = ControllerTypes::CONTROLLER_NONE;
s_detected = false;
s_status = NO_ADAPTER_DETECTED;
if (s_handle)
{
@ -377,7 +392,7 @@ GCPadStatus Input(int chan)
if (!UseAdapter())
return {};
if (s_handle == nullptr || !s_detected)
if (s_handle == nullptr || s_status != ADAPTER_DETECTED)
return {};
int payload_size = 0;
@ -497,7 +512,7 @@ void ResetRumble()
// being called while the libusb state is being reset
static void ResetRumbleLockNeeded()
{
if (!UseAdapter() || (s_handle == nullptr || !s_detected))
if (!UseAdapter() || (s_handle == nullptr || s_status != ADAPTER_DETECTED))
{
return;
}
@ -527,14 +542,20 @@ void Output(int chan, u8 rumble_command)
}
}
bool IsDetected()
bool IsDetected(const char** error_message)
{
return s_detected;
}
if (s_status >= 0)
{
if (error_message)
*error_message = nullptr;
bool IsDriverDetected()
{
return !s_libusb_driver_not_supported;
return s_status == ADAPTER_DETECTED;
}
if (error_message)
*error_message = libusb_strerror(static_cast<libusb_error>(s_status));
return false;
}
} // end of namespace GCAdapter

View File

@ -26,8 +26,7 @@ void StartScanThread();
void StopScanThread();
GCPadStatus Input(int chan);
void Output(int chan, u8 rumble_command);
bool IsDetected();
bool IsDriverDetected();
bool IsDetected(const char** error_message);
bool DeviceConnected(int chan);
void ResetDeviceType(int chan);
bool UseAdapter();