mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Move libusb utilities to LibusbUtils
* Simplifies libusb context usage and allows us to set options for all contexts easily. Notably, this lets us enable usbdk support in libusb, which is now opt-in in the latest version. * Moves the libusb config descriptor wrapper class to LibusbUtils too since that could easily be reused. * Moves device listing to LibusbUtils too and add a lock around it as some libusb backends are not thread safe. * Consequences: only a single context and a single event handling thread is used now, which is more efficient.
This commit is contained in:
127
Source/Core/Core/LibusbUtils.cpp
Normal file
127
Source/Core/Core/LibusbUtils.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#if defined(__LIBUSB__)
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Flag.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Core/LibusbUtils.h"
|
||||
|
||||
namespace LibusbUtils
|
||||
{
|
||||
#if defined(__LIBUSB__)
|
||||
class Context::Impl
|
||||
{
|
||||
public:
|
||||
Impl()
|
||||
{
|
||||
const int ret = libusb_init(&m_context);
|
||||
ASSERT_MSG(IOS_USB, ret == LIBUSB_SUCCESS, "Failed to init libusb: %s", libusb_error_name(ret));
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
libusb_set_option(m_context, LIBUSB_OPTION_USE_USBDK);
|
||||
#endif
|
||||
m_event_thread_running.Set();
|
||||
m_event_thread = std::thread(&Impl::EventThread, this);
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
if (!m_context || !m_event_thread_running.TestAndClear())
|
||||
return;
|
||||
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000105
|
||||
libusb_interrupt_event_handler(m_context);
|
||||
#endif
|
||||
m_event_thread.join();
|
||||
libusb_exit(m_context);
|
||||
}
|
||||
|
||||
libusb_context* GetContext() { return m_context; }
|
||||
|
||||
bool GetDeviceList(GetDeviceListCallback callback)
|
||||
{
|
||||
std::lock_guard lock{m_device_list_mutex};
|
||||
|
||||
libusb_device** list;
|
||||
ssize_t count = libusb_get_device_list(m_context, &list);
|
||||
if (count < 0)
|
||||
return false;
|
||||
|
||||
for (ssize_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (!callback(list[i]))
|
||||
break;
|
||||
}
|
||||
libusb_free_device_list(list, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void EventThread()
|
||||
{
|
||||
Common::SetCurrentThreadName("libusb thread");
|
||||
timeval tv{5, 0};
|
||||
while (m_event_thread_running.IsSet())
|
||||
libusb_handle_events_timeout_completed(m_context, &tv, nullptr);
|
||||
}
|
||||
|
||||
libusb_context* m_context = nullptr;
|
||||
std::mutex m_device_list_mutex;
|
||||
Common::Flag m_event_thread_running;
|
||||
std::thread m_event_thread;
|
||||
};
|
||||
#else
|
||||
class Context::Impl
|
||||
{
|
||||
public:
|
||||
libusb_context* GetContext() { return nullptr; }
|
||||
bool GetDeviceList(GetDeviceListCallback callback) { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
Context::Context() : m_impl{std::make_unique<Impl>()}
|
||||
{
|
||||
}
|
||||
|
||||
Context::~Context() = default;
|
||||
|
||||
Context::operator libusb_context*() const
|
||||
{
|
||||
return m_impl->GetContext();
|
||||
}
|
||||
|
||||
bool Context::IsValid() const
|
||||
{
|
||||
return m_impl->GetContext() != nullptr;
|
||||
}
|
||||
|
||||
bool Context::GetDeviceList(GetDeviceListCallback callback)
|
||||
{
|
||||
return m_impl->GetDeviceList(std::move(callback));
|
||||
}
|
||||
|
||||
Context& GetContext()
|
||||
{
|
||||
static Context s_context;
|
||||
return s_context;
|
||||
}
|
||||
|
||||
ConfigDescriptor MakeConfigDescriptor(libusb_device* device, u8 config_num)
|
||||
{
|
||||
#if defined(__LIBUSB__)
|
||||
libusb_config_descriptor* descriptor = nullptr;
|
||||
if (libusb_get_config_descriptor(device, config_num, &descriptor) == LIBUSB_SUCCESS)
|
||||
return {descriptor, libusb_free_config_descriptor};
|
||||
#endif
|
||||
return {nullptr, [](auto) {}};
|
||||
}
|
||||
} // namespace LibusbUtils
|
Reference in New Issue
Block a user