Merge pull request #9033 from leoetlino/scan-thread
IOS/USB: Move scan thread logic into a separate class
This commit is contained in:
commit
936702bd04
|
@ -31,19 +31,16 @@ USBHost::USBHost(Kernel& ios, const std::string& device_name) : Device(ios, devi
|
|||
{
|
||||
}
|
||||
|
||||
USBHost::~USBHost()
|
||||
{
|
||||
StopThreads();
|
||||
}
|
||||
USBHost::~USBHost() = default;
|
||||
|
||||
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
||||
{
|
||||
if (!m_has_initialised && !Core::WantsDeterminism())
|
||||
{
|
||||
StartThreads();
|
||||
GetScanThread().Start();
|
||||
// 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_first_scan_complete_event.Wait();
|
||||
GetScanThread().WaitForFirstScan();
|
||||
m_has_initialised = true;
|
||||
}
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
|
@ -52,9 +49,9 @@ IPCCommandResult USBHost::Open(const OpenRequest& request)
|
|||
void USBHost::UpdateWantDeterminism(const bool new_want_determinism)
|
||||
{
|
||||
if (new_want_determinism)
|
||||
StopThreads();
|
||||
GetScanThread().Stop();
|
||||
else if (IsOpened())
|
||||
StartThreads();
|
||||
GetScanThread().Start();
|
||||
}
|
||||
|
||||
void USBHost::DoState(PointerWrap& p)
|
||||
|
@ -112,7 +109,6 @@ bool USBHost::UpdateDevices(const bool always_add_hooks)
|
|||
return false;
|
||||
DetectRemovedDevices(plugged_devices, hooks);
|
||||
DispatchHooks(hooks);
|
||||
m_first_scan_complete_event.Set();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -177,33 +173,44 @@ void USBHost::DispatchHooks(const DeviceChangeHooks& hooks)
|
|||
OnDeviceChangeEnd();
|
||||
}
|
||||
|
||||
void USBHost::StartThreads()
|
||||
USBHost::ScanThread::~ScanThread()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void USBHost::ScanThread::WaitForFirstScan()
|
||||
{
|
||||
m_first_scan_complete_event.Wait();
|
||||
}
|
||||
|
||||
void USBHost::ScanThread::Start()
|
||||
{
|
||||
if (Core::WantsDeterminism())
|
||||
return;
|
||||
|
||||
if (m_scan_thread_running.TestAndSet())
|
||||
if (m_thread_running.TestAndSet())
|
||||
{
|
||||
m_scan_thread = std::thread([this] {
|
||||
m_thread = std::thread([this] {
|
||||
Common::SetCurrentThreadName("USB Scan Thread");
|
||||
while (m_scan_thread_running.IsSet())
|
||||
while (m_thread_running.IsSet())
|
||||
{
|
||||
UpdateDevices();
|
||||
if (m_host->UpdateDevices())
|
||||
m_first_scan_complete_event.Set();
|
||||
Common::SleepCurrentThread(50);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void USBHost::StopThreads()
|
||||
void USBHost::ScanThread::Stop()
|
||||
{
|
||||
if (m_scan_thread_running.TestAndClear())
|
||||
m_scan_thread.join();
|
||||
if (m_thread_running.TestAndClear())
|
||||
m_thread.join();
|
||||
|
||||
// Clear all devices and dispatch removal hooks.
|
||||
DeviceChangeHooks hooks;
|
||||
DetectRemovedDevices(std::set<u64>(), hooks);
|
||||
DispatchHooks(hooks);
|
||||
m_host->DetectRemovedDevices(std::set<u64>(), hooks);
|
||||
m_host->DispatchHooks(hooks);
|
||||
}
|
||||
|
||||
IPCCommandResult USBHost::HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||
|
|
|
@ -46,6 +46,23 @@ protected:
|
|||
};
|
||||
using DeviceChangeHooks = std::map<std::shared_ptr<USB::Device>, ChangeEvent>;
|
||||
|
||||
class ScanThread final
|
||||
{
|
||||
public:
|
||||
explicit ScanThread(USBHost* host) : m_host(host) {}
|
||||
~ScanThread();
|
||||
void Start();
|
||||
void Stop();
|
||||
void WaitForFirstScan();
|
||||
|
||||
private:
|
||||
USBHost* m_host = nullptr;
|
||||
Common::Flag m_thread_running;
|
||||
std::thread m_thread;
|
||||
Common::Event m_first_scan_complete_event;
|
||||
Common::Flag m_is_initialized;
|
||||
};
|
||||
|
||||
std::map<u64, std::shared_ptr<USB::Device>> m_devices;
|
||||
mutable std::mutex m_devices_mutex;
|
||||
|
||||
|
@ -53,25 +70,18 @@ protected:
|
|||
virtual void OnDeviceChange(ChangeEvent event, std::shared_ptr<USB::Device> changed_device);
|
||||
virtual void OnDeviceChangeEnd();
|
||||
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
||||
virtual ScanThread& GetScanThread() = 0;
|
||||
|
||||
IPCCommandResult HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||
std::function<s32()> submit) const;
|
||||
|
||||
private:
|
||||
void StartThreads();
|
||||
void StopThreads();
|
||||
|
||||
bool AddDevice(std::unique_ptr<USB::Device> device);
|
||||
bool UpdateDevices(bool always_add_hooks = false);
|
||||
|
||||
bool AddNewDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks, bool always_add_hooks);
|
||||
void DetectRemovedDevices(const std::set<u64>& plugged_devices, DeviceChangeHooks& hooks);
|
||||
void DispatchHooks(const DeviceChangeHooks& hooks);
|
||||
|
||||
// Device scanning thread
|
||||
Common::Flag m_scan_thread_running;
|
||||
std::thread m_scan_thread;
|
||||
Common::Event m_first_scan_complete_event;
|
||||
bool m_has_initialised = false;
|
||||
LibusbUtils::Context m_context;
|
||||
};
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace IOS::HLE::Device
|
|||
{
|
||||
OH0::OH0(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name)
|
||||
{
|
||||
static_assert(offsetof(OH0, m_scan_thread) == sizeof(OH0) - sizeof(ScanThread),
|
||||
"ScanThread must be the last data member");
|
||||
}
|
||||
|
||||
IPCCommandResult OH0::Open(const OpenRequest& request)
|
||||
|
|
|
@ -66,6 +66,8 @@ private:
|
|||
template <typename T>
|
||||
void TriggerHook(std::map<T, u32>& hooks, T value, ReturnCode return_value);
|
||||
|
||||
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||
|
||||
struct DeviceEntry
|
||||
{
|
||||
u32 unknown;
|
||||
|
@ -79,6 +81,8 @@ private:
|
|||
std::map<u64, u32> m_removal_hooks;
|
||||
std::set<u64> m_opened_devices;
|
||||
std::mutex m_hooks_mutex;
|
||||
|
||||
ScanThread m_scan_thread{this};
|
||||
};
|
||||
} // namespace Device
|
||||
} // namespace IOS::HLE
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace IOS::HLE::Device
|
|||
{
|
||||
USB_HIDv4::USB_HIDv4(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name)
|
||||
{
|
||||
static_assert(offsetof(USB_HIDv4, m_scan_thread) == sizeof(USB_HIDv4) - sizeof(ScanThread),
|
||||
"ScanThread must be the last data member");
|
||||
}
|
||||
|
||||
IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
std::vector<u8> GetDeviceEntry(const USB::Device& device) const;
|
||||
void OnDeviceChange(ChangeEvent, std::shared_ptr<USB::Device>) override;
|
||||
bool ShouldAddDevice(const USB::Device& device) const override;
|
||||
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||
|
||||
static constexpr u32 VERSION = 0x40001;
|
||||
static constexpr u8 HID_CLASS = 0x03;
|
||||
|
@ -51,5 +52,7 @@ private:
|
|||
// IOS device IDs <=> USB device IDs
|
||||
std::map<s32, u64> m_ios_ids;
|
||||
std::map<u64, s32> m_device_ids;
|
||||
|
||||
ScanThread m_scan_thread{this};
|
||||
};
|
||||
} // namespace IOS::HLE::Device
|
||||
|
|
|
@ -22,6 +22,9 @@ USB_HIDv5::~USB_HIDv5() = default;
|
|||
|
||||
IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
||||
{
|
||||
static_assert(offsetof(USB_HIDv5, m_scan_thread) == sizeof(USB_HIDv5) - sizeof(ScanThread),
|
||||
"ScanThread must be the last data member");
|
||||
|
||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||
switch (request.request)
|
||||
{
|
||||
|
|
|
@ -27,11 +27,16 @@ private:
|
|||
|
||||
bool ShouldAddDevice(const USB::Device& device) const override;
|
||||
bool HasInterfaceNumberInIDs() const override { return true; }
|
||||
|
||||
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||
|
||||
struct AdditionalDeviceData
|
||||
{
|
||||
u8 interrupt_in_endpoint = 0;
|
||||
u8 interrupt_out_endpoint = 0;
|
||||
};
|
||||
std::array<AdditionalDeviceData, 32> m_additional_device_data{};
|
||||
|
||||
ScanThread m_scan_thread{this};
|
||||
};
|
||||
} // namespace IOS::HLE::Device
|
||||
|
|
|
@ -22,6 +22,9 @@ USB_VEN::~USB_VEN() = default;
|
|||
|
||||
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
||||
{
|
||||
static_assert(offsetof(USB_VEN, m_scan_thread) == sizeof(USB_VEN) - sizeof(ScanThread),
|
||||
"ScanThread must be the last data member");
|
||||
|
||||
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||
switch (request.request)
|
||||
{
|
||||
|
|
|
@ -26,5 +26,9 @@ private:
|
|||
|
||||
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv);
|
||||
bool HasInterfaceNumberInIDs() const override { return false; }
|
||||
|
||||
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||
|
||||
ScanThread m_scan_thread{this};
|
||||
};
|
||||
} // namespace IOS::HLE::Device
|
||||
|
|
Loading…
Reference in New Issue