IOS: Only have one USBScanner
Some games open two USB interfaces, e.g. /dev/usb/oh0 and /dev/usb/hid. This was causing us to run two scanning threads at once, using up more CPU time for scanning than we need to.
This commit is contained in:
parent
e63ac918ac
commit
8cc6ba6279
|
@ -154,6 +154,7 @@ add_library(common
|
|||
VariantUtil.h
|
||||
Version.cpp
|
||||
Version.h
|
||||
WaitableFlag.h
|
||||
WindowSystemInfo.h
|
||||
WorkQueueThread.h
|
||||
)
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <concrt.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Wrapper around Flag that lets callers wait for the flag to change.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common/Flag.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class WaitableFlag final
|
||||
{
|
||||
public:
|
||||
void Set(bool value = true)
|
||||
{
|
||||
if (m_flag.TestAndSet(value))
|
||||
{
|
||||
// Lock and immediately unlock m_mutex.
|
||||
{
|
||||
// Holding the lock at any time between the change of our flag and notify call
|
||||
// is sufficient to prevent a race where both of these actions
|
||||
// happen between the other thread's predicate test and wait call
|
||||
// which would cause wait to block until the next spurious wakeup or timeout.
|
||||
|
||||
// Unlocking before notification is a micro-optimization to prevent
|
||||
// the notified thread from immediately blocking on the mutex.
|
||||
std::lock_guard<std::mutex> lk(m_mutex);
|
||||
}
|
||||
|
||||
m_condvar.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() { Set(false); }
|
||||
|
||||
void Wait(bool expected_value)
|
||||
{
|
||||
if (m_flag.IsSet() == expected_value)
|
||||
return;
|
||||
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_condvar.wait(lk, [&] { return m_flag.IsSet() == expected_value; });
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool WaitFor(bool expected_value, const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
if (m_flag.IsSet() == expected_value)
|
||||
return true;
|
||||
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
bool signaled =
|
||||
m_condvar.wait_for(lk, rel_time, [&] { return m_flag.IsSet() == expected_value; });
|
||||
|
||||
return signaled;
|
||||
}
|
||||
|
||||
private:
|
||||
Flag m_flag;
|
||||
std::condition_variable m_condvar;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace Common
|
|
@ -15,6 +15,11 @@
|
|||
|
||||
namespace IOS::HLE::USB
|
||||
{
|
||||
EmulationKernel& TransferCommand::GetEmulationKernel() const
|
||||
{
|
||||
return m_ios;
|
||||
}
|
||||
|
||||
std::unique_ptr<u8[]> TransferCommand::MakeBuffer(const size_t size) const
|
||||
{
|
||||
ASSERT_MSG(IOS_USB, data_address != 0, "Invalid data_address");
|
||||
|
|
|
@ -106,6 +106,8 @@ struct TransferCommand
|
|||
{
|
||||
}
|
||||
virtual ~TransferCommand() = default;
|
||||
|
||||
EmulationKernel& GetEmulationKernel() const;
|
||||
// Called after a transfer has completed to reply to the IPC request.
|
||||
// This can be overridden for additional processing before replying.
|
||||
virtual void OnTransferComplete(s32 return_value) const;
|
||||
|
|
|
@ -137,7 +137,7 @@ static constexpr std::array<u8, 32> SHA1_CONSTANT = {
|
|||
static constexpr std::array<u8, 16> BLANK_BLOCK = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
InfinityUSB::InfinityUSB(EmulationKernel& ios) : m_ios(ios)
|
||||
InfinityUSB::InfinityUSB()
|
||||
{
|
||||
m_vid = 0x0E6F;
|
||||
m_pid = 0x0129;
|
||||
|
@ -241,7 +241,7 @@ int InfinityUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
|
|||
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Interrupt: length={:04x} endpoint={:02x}", m_vid,
|
||||
m_pid, m_active_interface, cmd->length, cmd->endpoint);
|
||||
|
||||
auto& system = m_ios.GetSystem();
|
||||
auto& system = cmd->GetEmulationKernel().GetSystem();
|
||||
auto& memory = system.GetMemory();
|
||||
auto& infinity_base = system.GetInfinityBase();
|
||||
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct InfinityFigure final
|
|||
class InfinityUSB final : public Device
|
||||
{
|
||||
public:
|
||||
InfinityUSB(EmulationKernel& ios);
|
||||
InfinityUSB();
|
||||
~InfinityUSB() override;
|
||||
DeviceDescriptor GetDeviceDescriptor() const override;
|
||||
std::vector<ConfigDescriptor> GetConfigurations() const override;
|
||||
|
@ -53,7 +53,6 @@ private:
|
|||
void ScheduleTransfer(std::unique_ptr<TransferCommand> command, const std::array<u8, 32>& data,
|
||||
u64 expected_time_us);
|
||||
|
||||
EmulationKernel& m_ios;
|
||||
u16 m_vid = 0;
|
||||
u16 m_pid = 0;
|
||||
u8 m_active_interface = 0;
|
||||
|
|
|
@ -612,7 +612,7 @@ const std::map<const std::pair<const u16, const u16>, SkyData> list_skylanders =
|
|||
{{3503, 0x4000}, {"Kaos Trophy", Game::Superchargers, Element::Other, Type::Trophy}},
|
||||
};
|
||||
|
||||
SkylanderUSB::SkylanderUSB(EmulationKernel& ios) : m_ios(ios)
|
||||
SkylanderUSB::SkylanderUSB()
|
||||
{
|
||||
m_vid = 0x1430;
|
||||
m_pid = 0x0150;
|
||||
|
@ -741,7 +741,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
|||
else
|
||||
{
|
||||
// Skylander Portal Requests
|
||||
auto& system = m_ios.GetSystem();
|
||||
auto& system = cmd->GetEmulationKernel().GetSystem();
|
||||
auto& memory = system.GetMemory();
|
||||
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
|
||||
if (cmd->length == 0 || buf == nullptr)
|
||||
|
@ -1028,7 +1028,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
|
|||
DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Interrupt: length={} endpoint={}", m_vid, m_pid,
|
||||
m_active_interface, cmd->length, cmd->endpoint);
|
||||
|
||||
auto& system = m_ios.GetSystem();
|
||||
auto& system = cmd->GetEmulationKernel().GetSystem();
|
||||
auto& memory = system.GetMemory();
|
||||
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
|
||||
if (cmd->length == 0 || buf == nullptr)
|
||||
|
|
|
@ -72,7 +72,7 @@ extern const std::map<const std::pair<const u16, const u16>, SkyData> list_skyla
|
|||
class SkylanderUSB final : public Device
|
||||
{
|
||||
public:
|
||||
SkylanderUSB(EmulationKernel& ios);
|
||||
SkylanderUSB();
|
||||
~SkylanderUSB();
|
||||
DeviceDescriptor GetDeviceDescriptor() const override;
|
||||
std::vector<ConfigDescriptor> GetConfigurations() const override;
|
||||
|
@ -92,7 +92,6 @@ public:
|
|||
s32 expected_count, u64 expected_time_us);
|
||||
|
||||
private:
|
||||
EmulationKernel& m_ios;
|
||||
u16 m_vid = 0;
|
||||
u16 m_pid = 0;
|
||||
u8 m_active_interface = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Core/Core.h"
|
||||
#include "Core/IOS/USB/Common.h"
|
||||
#include "Core/IOS/USB/USBScanner.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace IOS::HLE
|
||||
{
|
||||
|
@ -27,18 +28,18 @@ USBHost::USBHost(EmulationKernel& ios, const std::string& device_name)
|
|||
|
||||
USBHost::~USBHost()
|
||||
{
|
||||
m_usb_scanner.Stop();
|
||||
GetSystem().GetUSBScanner().RemoveClient(this);
|
||||
}
|
||||
|
||||
std::optional<IPCReply> USBHost::Open(const OpenRequest& request)
|
||||
{
|
||||
if (!m_has_initialised)
|
||||
{
|
||||
m_usb_scanner.Start();
|
||||
GetSystem().GetUSBScanner().AddClient(this);
|
||||
// Force a device scan to complete, because some games (including Your Shape) only care
|
||||
// about the initial device list (in the first GETDEVICECHANGE reply).
|
||||
m_usb_scanner.WaitForFirstScan();
|
||||
OnDevicesChangedInternal(m_usb_scanner.GetDevices());
|
||||
GetSystem().GetUSBScanner().WaitForFirstScan();
|
||||
OnDevicesChangedInternal(GetSystem().GetUSBScanner().GetDevices());
|
||||
m_has_initialised = true;
|
||||
}
|
||||
return IPCReply(IPC_SUCCESS);
|
||||
|
@ -53,7 +54,7 @@ void USBHost::DoState(PointerWrap& p)
|
|||
// already plugged in, and which need to be triggered.
|
||||
std::lock_guard lk(m_devices_mutex);
|
||||
m_devices.clear();
|
||||
OnDevicesChanged(m_usb_scanner.GetDevices());
|
||||
OnDevicesChanged(GetSystem().GetUSBScanner().GetDevices());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ bool USBHost::ShouldAddDevice(const USB::Device& device) const
|
|||
void USBHost::Update()
|
||||
{
|
||||
if (Core::WantsDeterminism())
|
||||
OnDevicesChangedInternal(m_usb_scanner.GetDevices());
|
||||
OnDevicesChangedInternal(GetSystem().GetUSBScanner().GetDevices());
|
||||
}
|
||||
|
||||
void USBHost::OnDevicesChanged(const USBScanner::DeviceMap& new_devices)
|
||||
|
@ -118,7 +119,7 @@ void USBHost::OnDevicesChangedInternal(const USBScanner::DeviceMap& new_devices)
|
|||
|
||||
for (const auto& [id, device] : new_devices)
|
||||
{
|
||||
if (!m_devices.contains(id))
|
||||
if (!m_devices.contains(id) && ShouldAddDevice(*device))
|
||||
{
|
||||
INFO_LOG_FMT(IOS_USB, "{} - New device: {:04x}:{:04x}", GetDeviceName(), device->GetVid(),
|
||||
device->GetPid());
|
||||
|
|
|
@ -31,8 +31,6 @@ public:
|
|||
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
||||
|
||||
void OnDevicesChanged(const USBScanner::DeviceMap& new_devices);
|
||||
|
||||
protected:
|
||||
|
@ -46,6 +44,7 @@ protected:
|
|||
std::shared_ptr<USB::Device> GetDeviceById(u64 device_id) const;
|
||||
virtual void OnDeviceChange(ChangeEvent event, std::shared_ptr<USB::Device> changed_device);
|
||||
virtual void OnDeviceChangeEnd();
|
||||
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
||||
|
||||
std::optional<IPCReply> HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||
std::function<s32()> submit) const;
|
||||
|
@ -53,8 +52,6 @@ protected:
|
|||
std::map<u64, std::shared_ptr<USB::Device>> m_devices;
|
||||
mutable std::recursive_mutex m_devices_mutex;
|
||||
|
||||
USBScanner m_usb_scanner{this};
|
||||
|
||||
private:
|
||||
void Update() override;
|
||||
void OnDevicesChangedInternal(const USBScanner::DeviceMap& new_devices);
|
||||
|
|
|
@ -25,9 +25,8 @@
|
|||
|
||||
namespace IOS::HLE::USB
|
||||
{
|
||||
LibusbDevice::LibusbDevice(EmulationKernel& ios, libusb_device* device,
|
||||
const libusb_device_descriptor& descriptor)
|
||||
: m_ios(ios), m_device(device)
|
||||
LibusbDevice::LibusbDevice(libusb_device* device, const libusb_device_descriptor& descriptor)
|
||||
: m_device(device)
|
||||
{
|
||||
libusb_ref_device(m_device);
|
||||
m_vid = descriptor.idVendor;
|
||||
|
@ -226,7 +225,7 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
|||
}
|
||||
const int ret = SetAltSetting(static_cast<u8>(cmd->value));
|
||||
if (ret == LIBUSB_SUCCESS)
|
||||
m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length);
|
||||
cmd->GetEmulationKernel().EnqueueIPCReply(cmd->ios_request, cmd->length);
|
||||
return ret;
|
||||
}
|
||||
case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_DEVICE, REQUEST_SET_CONFIGURATION):
|
||||
|
@ -238,7 +237,7 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
|||
if (ret == LIBUSB_SUCCESS)
|
||||
{
|
||||
ClaimAllInterfaces(cmd->value);
|
||||
m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length);
|
||||
cmd->GetEmulationKernel().EnqueueIPCReply(cmd->ios_request, cmd->length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -249,7 +248,7 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
|||
libusb_fill_control_setup(buffer.get(), cmd->request_type, cmd->request, cmd->value, cmd->index,
|
||||
cmd->length);
|
||||
|
||||
auto& system = m_ios.GetSystem();
|
||||
auto& system = cmd->GetEmulationKernel().GetSystem();
|
||||
auto& memory = system.GetMemory();
|
||||
memory.CopyFromEmu(buffer.get() + LIBUSB_CONTROL_SETUP_SIZE, cmd->data_address, cmd->length);
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@ namespace IOS::HLE::USB
|
|||
class LibusbDevice final : public Device
|
||||
{
|
||||
public:
|
||||
LibusbDevice(EmulationKernel& ios, libusb_device* device,
|
||||
const libusb_device_descriptor& device_descriptor);
|
||||
LibusbDevice(libusb_device* device, const libusb_device_descriptor& device_descriptor);
|
||||
~LibusbDevice();
|
||||
DeviceDescriptor GetDeviceDescriptor() const override;
|
||||
std::vector<ConfigDescriptor> GetConfigurations() const override;
|
||||
|
@ -46,8 +45,6 @@ public:
|
|||
int SubmitTransfer(std::unique_ptr<IsoMessage> message) override;
|
||||
|
||||
private:
|
||||
EmulationKernel& m_ios;
|
||||
|
||||
std::vector<LibusbUtils::ConfigDescriptor> m_config_descriptors;
|
||||
u16 m_vid = 0;
|
||||
u16 m_pid = 0;
|
||||
|
|
|
@ -30,24 +30,66 @@
|
|||
|
||||
namespace IOS::HLE
|
||||
{
|
||||
USBScanner::USBScanner(USBHost* host) : m_host(host)
|
||||
{
|
||||
}
|
||||
|
||||
USBScanner::~USBScanner()
|
||||
{
|
||||
Stop();
|
||||
StopScanning();
|
||||
}
|
||||
|
||||
void USBScanner::WaitForFirstScan()
|
||||
{
|
||||
if (m_thread_running.IsSet())
|
||||
{
|
||||
m_first_scan_complete_event.Wait();
|
||||
m_first_scan_complete_flag.Wait(true);
|
||||
}
|
||||
}
|
||||
|
||||
void USBScanner::Start()
|
||||
bool USBScanner::AddClient(USBHost* client)
|
||||
{
|
||||
bool should_start_scanning = false;
|
||||
bool client_is_new = true;
|
||||
|
||||
std::lock_guard thread_lock(m_thread_start_stop_mutex);
|
||||
|
||||
{
|
||||
std::lock_guard clients_lock(m_clients_mutex);
|
||||
should_start_scanning = m_clients.empty();
|
||||
auto [it, newly_added] = m_clients.insert(client);
|
||||
client_is_new = newly_added;
|
||||
}
|
||||
|
||||
if (should_start_scanning)
|
||||
StartScanning();
|
||||
|
||||
return client_is_new;
|
||||
}
|
||||
|
||||
bool USBScanner::RemoveClient(USBHost* client)
|
||||
{
|
||||
std::lock_guard thread_lock(m_thread_start_stop_mutex);
|
||||
|
||||
bool client_was_removed;
|
||||
bool should_join_scan_thread = false;
|
||||
|
||||
{
|
||||
std::lock_guard clients_lock(m_clients_mutex);
|
||||
|
||||
const bool was_empty = m_clients.empty();
|
||||
client_was_removed = m_clients.erase(client) != 0;
|
||||
|
||||
const bool should_stop_scanning = !was_empty && m_clients.empty();
|
||||
if (should_stop_scanning)
|
||||
should_join_scan_thread = m_thread_running.TestAndClear();
|
||||
}
|
||||
|
||||
// The scan thread might be trying to lock m_clients_mutex, so we need to not hold a lock on
|
||||
// m_clients_mutex when trying to join with the scan thread.
|
||||
if (should_join_scan_thread)
|
||||
m_thread.join();
|
||||
|
||||
return client_was_removed;
|
||||
}
|
||||
|
||||
void USBScanner::StartScanning()
|
||||
{
|
||||
if (m_thread_running.TestAndSet())
|
||||
{
|
||||
|
@ -56,14 +98,16 @@ void USBScanner::Start()
|
|||
while (m_thread_running.IsSet())
|
||||
{
|
||||
if (UpdateDevices())
|
||||
m_first_scan_complete_event.Set();
|
||||
m_first_scan_complete_flag.Set(true);
|
||||
Common::SleepCurrentThread(50);
|
||||
}
|
||||
m_devices.clear();
|
||||
m_first_scan_complete_flag.Set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void USBScanner::Stop()
|
||||
void USBScanner::StopScanning()
|
||||
{
|
||||
if (m_thread_running.TestAndClear())
|
||||
m_thread.join();
|
||||
|
@ -86,7 +130,10 @@ bool USBScanner::UpdateDevices()
|
|||
if (!std::ranges::equal(std::views::keys(m_devices), std::views::keys(new_devices)))
|
||||
{
|
||||
m_devices = std::move(new_devices);
|
||||
m_host->OnDevicesChanged(m_devices);
|
||||
|
||||
std::lock_guard clients_lock(m_clients_mutex);
|
||||
for (USBHost* client : m_clients)
|
||||
client->OnDevicesChanged(m_devices);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -110,8 +157,7 @@ bool USBScanner::AddNewDevices(DeviceMap* new_devices) const
|
|||
if (!whitelist.contains({descriptor.idVendor, descriptor.idProduct}))
|
||||
return true;
|
||||
|
||||
auto usb_device =
|
||||
std::make_unique<USB::LibusbDevice>(m_host->GetEmulationKernel(), device, descriptor);
|
||||
auto usb_device = std::make_unique<USB::LibusbDevice>(device, descriptor);
|
||||
AddDevice(std::move(usb_device), new_devices);
|
||||
return true;
|
||||
});
|
||||
|
@ -123,24 +169,23 @@ bool USBScanner::AddNewDevices(DeviceMap* new_devices) const
|
|||
return true;
|
||||
}
|
||||
|
||||
void USBScanner::AddEmulatedDevices(DeviceMap* new_devices) const
|
||||
void USBScanner::AddEmulatedDevices(DeviceMap* new_devices)
|
||||
{
|
||||
if (Config::Get(Config::MAIN_EMULATE_SKYLANDER_PORTAL) && !NetPlay::IsNetPlayRunning())
|
||||
{
|
||||
auto skylanderportal = std::make_unique<USB::SkylanderUSB>(m_host->GetEmulationKernel());
|
||||
auto skylanderportal = std::make_unique<USB::SkylanderUSB>();
|
||||
AddDevice(std::move(skylanderportal), new_devices);
|
||||
}
|
||||
if (Config::Get(Config::MAIN_EMULATE_INFINITY_BASE) && !NetPlay::IsNetPlayRunning())
|
||||
{
|
||||
auto infinity_base = std::make_unique<USB::InfinityUSB>(m_host->GetEmulationKernel());
|
||||
auto infinity_base = std::make_unique<USB::InfinityUSB>();
|
||||
AddDevice(std::move(infinity_base), new_devices);
|
||||
}
|
||||
}
|
||||
|
||||
void USBScanner::AddDevice(std::unique_ptr<USB::Device> device, DeviceMap* new_devices) const
|
||||
void USBScanner::AddDevice(std::unique_ptr<USB::Device> device, DeviceMap* new_devices)
|
||||
{
|
||||
if (m_host->ShouldAddDevice(*device))
|
||||
(*new_devices)[device->GetId()] = std::move(device);
|
||||
(*new_devices)[device->GetId()] = std::move(device);
|
||||
}
|
||||
|
||||
} // namespace IOS::HLE
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include <thread>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Flag.h"
|
||||
#include "Common/WaitableFlag.h"
|
||||
#include "Core/IOS/USB/Common.h"
|
||||
#include "Core/LibusbUtils.h"
|
||||
|
||||
|
@ -26,28 +26,34 @@ class USBScanner final
|
|||
public:
|
||||
using DeviceMap = std::map<u64, std::shared_ptr<USB::Device>>;
|
||||
|
||||
explicit USBScanner(USBHost* host);
|
||||
~USBScanner();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
bool AddClient(USBHost* client);
|
||||
bool RemoveClient(USBHost* client);
|
||||
|
||||
void WaitForFirstScan();
|
||||
|
||||
DeviceMap GetDevices() const;
|
||||
|
||||
private:
|
||||
void StartScanning();
|
||||
void StopScanning();
|
||||
|
||||
bool UpdateDevices();
|
||||
bool AddNewDevices(DeviceMap* new_devices) const;
|
||||
void AddEmulatedDevices(DeviceMap* new_devices) const;
|
||||
void AddDevice(std::unique_ptr<USB::Device> device, DeviceMap* new_devices) const;
|
||||
static void AddEmulatedDevices(DeviceMap* new_devices);
|
||||
static void AddDevice(std::unique_ptr<USB::Device> device, DeviceMap* new_devices);
|
||||
|
||||
DeviceMap m_devices;
|
||||
mutable std::mutex m_devices_mutex;
|
||||
|
||||
USBHost* m_host = nullptr;
|
||||
std::set<USBHost*> m_clients;
|
||||
std::mutex m_clients_mutex;
|
||||
|
||||
Common::Flag m_thread_running;
|
||||
std::thread m_thread;
|
||||
Common::Event m_first_scan_complete_event;
|
||||
std::mutex m_thread_start_stop_mutex;
|
||||
Common::WaitableFlag m_first_scan_complete_flag;
|
||||
|
||||
LibusbUtils::Context m_context;
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "IOS/USB/Emulated/Infinity.h"
|
||||
#include "IOS/USB/Emulated/Skylanders/Skylander.h"
|
||||
#include "IOS/USB/USBScanner.h"
|
||||
#include "VideoCommon/Assets/CustomAssetLoader.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
|
@ -89,6 +90,7 @@ struct System::Impl
|
|||
SerialInterface::SerialInterfaceManager m_serial_interface;
|
||||
Sram m_sram;
|
||||
SystemTimers::SystemTimersManager m_system_timers;
|
||||
IOS::HLE::USBScanner m_usb_scanner;
|
||||
VertexShaderManager m_vertex_shader_manager;
|
||||
XFStateManager m_xf_state_manager;
|
||||
VideoInterface::VideoInterfaceManager m_video_interface;
|
||||
|
@ -313,6 +315,11 @@ SystemTimers::SystemTimersManager& System::GetSystemTimers() const
|
|||
return m_impl->m_system_timers;
|
||||
}
|
||||
|
||||
IOS::HLE::USBScanner& System::GetUSBScanner() const
|
||||
{
|
||||
return m_impl->m_usb_scanner;
|
||||
}
|
||||
|
||||
VertexShaderManager& System::GetVertexShaderManager() const
|
||||
{
|
||||
return m_impl->m_vertex_shader_manager;
|
||||
|
|
|
@ -56,7 +56,8 @@ class GPFifoManager;
|
|||
namespace IOS::HLE
|
||||
{
|
||||
class EmulationKernel;
|
||||
}
|
||||
class USBScanner;
|
||||
} // namespace IOS::HLE
|
||||
namespace HSP
|
||||
{
|
||||
class HSPManager;
|
||||
|
@ -190,6 +191,7 @@ public:
|
|||
SerialInterface::SerialInterfaceManager& GetSerialInterface() const;
|
||||
Sram& GetSRAM() const;
|
||||
SystemTimers::SystemTimersManager& GetSystemTimers() const;
|
||||
IOS::HLE::USBScanner& GetUSBScanner() const;
|
||||
VertexShaderManager& GetVertexShaderManager() const;
|
||||
XFStateManager& GetXFStateManager() const;
|
||||
VideoInterface::VideoInterfaceManager& GetVideoInterface() const;
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
<ClInclude Include="Common\UPnP.h" />
|
||||
<ClInclude Include="Common\VariantUtil.h" />
|
||||
<ClInclude Include="Common\Version.h" />
|
||||
<ClInclude Include="Common\WaitableFlag.h" />
|
||||
<ClInclude Include="Common\WindowsRegistry.h" />
|
||||
<ClInclude Include="Common\WindowSystemInfo.h" />
|
||||
<ClInclude Include="Common\WorkQueueThread.h" />
|
||||
|
|
Loading…
Reference in New Issue