mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-12 06:39:14 +01:00
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()
|
USBHost::~USBHost() = default;
|
||||||
{
|
|
||||||
StopThreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
if (!m_has_initialised && !Core::WantsDeterminism())
|
if (!m_has_initialised && !Core::WantsDeterminism())
|
||||||
{
|
{
|
||||||
StartThreads();
|
GetScanThread().Start();
|
||||||
// Force a device scan to complete, because some games (including Your Shape) only care
|
// Force a device scan to complete, because some games (including Your Shape) only care
|
||||||
// about the initial device list (in the first GETDEVICECHANGE reply).
|
// about the initial device list (in the first GETDEVICECHANGE reply).
|
||||||
m_first_scan_complete_event.Wait();
|
GetScanThread().WaitForFirstScan();
|
||||||
m_has_initialised = true;
|
m_has_initialised = true;
|
||||||
}
|
}
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
@ -52,9 +49,9 @@ IPCCommandResult USBHost::Open(const OpenRequest& request)
|
|||||||
void USBHost::UpdateWantDeterminism(const bool new_want_determinism)
|
void USBHost::UpdateWantDeterminism(const bool new_want_determinism)
|
||||||
{
|
{
|
||||||
if (new_want_determinism)
|
if (new_want_determinism)
|
||||||
StopThreads();
|
GetScanThread().Stop();
|
||||||
else if (IsOpened())
|
else if (IsOpened())
|
||||||
StartThreads();
|
GetScanThread().Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHost::DoState(PointerWrap& p)
|
void USBHost::DoState(PointerWrap& p)
|
||||||
@ -112,7 +109,6 @@ bool USBHost::UpdateDevices(const bool always_add_hooks)
|
|||||||
return false;
|
return false;
|
||||||
DetectRemovedDevices(plugged_devices, hooks);
|
DetectRemovedDevices(plugged_devices, hooks);
|
||||||
DispatchHooks(hooks);
|
DispatchHooks(hooks);
|
||||||
m_first_scan_complete_event.Set();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,33 +173,44 @@ void USBHost::DispatchHooks(const DeviceChangeHooks& hooks)
|
|||||||
OnDeviceChangeEnd();
|
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())
|
if (Core::WantsDeterminism())
|
||||||
return;
|
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");
|
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);
|
Common::SleepCurrentThread(50);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHost::StopThreads()
|
void USBHost::ScanThread::Stop()
|
||||||
{
|
{
|
||||||
if (m_scan_thread_running.TestAndClear())
|
if (m_thread_running.TestAndClear())
|
||||||
m_scan_thread.join();
|
m_thread.join();
|
||||||
|
|
||||||
// Clear all devices and dispatch removal hooks.
|
// Clear all devices and dispatch removal hooks.
|
||||||
DeviceChangeHooks hooks;
|
DeviceChangeHooks hooks;
|
||||||
DetectRemovedDevices(std::set<u64>(), hooks);
|
m_host->DetectRemovedDevices(std::set<u64>(), hooks);
|
||||||
DispatchHooks(hooks);
|
m_host->DispatchHooks(hooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult USBHost::HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
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>;
|
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;
|
std::map<u64, std::shared_ptr<USB::Device>> m_devices;
|
||||||
mutable std::mutex m_devices_mutex;
|
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 OnDeviceChange(ChangeEvent event, std::shared_ptr<USB::Device> changed_device);
|
||||||
virtual void OnDeviceChangeEnd();
|
virtual void OnDeviceChangeEnd();
|
||||||
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
virtual bool ShouldAddDevice(const USB::Device& device) const;
|
||||||
|
virtual ScanThread& GetScanThread() = 0;
|
||||||
|
|
||||||
IPCCommandResult HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
IPCCommandResult HandleTransfer(std::shared_ptr<USB::Device> device, u32 request,
|
||||||
std::function<s32()> submit) const;
|
std::function<s32()> submit) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void StartThreads();
|
|
||||||
void StopThreads();
|
|
||||||
|
|
||||||
bool AddDevice(std::unique_ptr<USB::Device> device);
|
bool AddDevice(std::unique_ptr<USB::Device> device);
|
||||||
bool UpdateDevices(bool always_add_hooks = false);
|
bool UpdateDevices(bool always_add_hooks = false);
|
||||||
|
|
||||||
bool AddNewDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks, bool always_add_hooks);
|
bool AddNewDevices(std::set<u64>& new_devices, DeviceChangeHooks& hooks, bool always_add_hooks);
|
||||||
void DetectRemovedDevices(const std::set<u64>& plugged_devices, DeviceChangeHooks& hooks);
|
void DetectRemovedDevices(const std::set<u64>& plugged_devices, DeviceChangeHooks& hooks);
|
||||||
void DispatchHooks(const 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;
|
bool m_has_initialised = false;
|
||||||
LibusbUtils::Context m_context;
|
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)
|
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)
|
IPCCommandResult OH0::Open(const OpenRequest& request)
|
||||||
|
@ -66,6 +66,8 @@ private:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void TriggerHook(std::map<T, u32>& hooks, T value, ReturnCode return_value);
|
void TriggerHook(std::map<T, u32>& hooks, T value, ReturnCode return_value);
|
||||||
|
|
||||||
|
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||||
|
|
||||||
struct DeviceEntry
|
struct DeviceEntry
|
||||||
{
|
{
|
||||||
u32 unknown;
|
u32 unknown;
|
||||||
@ -79,6 +81,8 @@ private:
|
|||||||
std::map<u64, u32> m_removal_hooks;
|
std::map<u64, u32> m_removal_hooks;
|
||||||
std::set<u64> m_opened_devices;
|
std::set<u64> m_opened_devices;
|
||||||
std::mutex m_hooks_mutex;
|
std::mutex m_hooks_mutex;
|
||||||
|
|
||||||
|
ScanThread m_scan_thread{this};
|
||||||
};
|
};
|
||||||
} // namespace Device
|
} // namespace Device
|
||||||
} // namespace IOS::HLE
|
} // 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)
|
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)
|
IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
||||||
|
@ -39,6 +39,7 @@ private:
|
|||||||
std::vector<u8> GetDeviceEntry(const USB::Device& device) const;
|
std::vector<u8> GetDeviceEntry(const USB::Device& device) const;
|
||||||
void OnDeviceChange(ChangeEvent, std::shared_ptr<USB::Device>) override;
|
void OnDeviceChange(ChangeEvent, std::shared_ptr<USB::Device>) override;
|
||||||
bool ShouldAddDevice(const USB::Device& device) const override;
|
bool ShouldAddDevice(const USB::Device& device) const override;
|
||||||
|
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||||
|
|
||||||
static constexpr u32 VERSION = 0x40001;
|
static constexpr u32 VERSION = 0x40001;
|
||||||
static constexpr u8 HID_CLASS = 0x03;
|
static constexpr u8 HID_CLASS = 0x03;
|
||||||
@ -51,5 +52,7 @@ private:
|
|||||||
// IOS device IDs <=> USB device IDs
|
// IOS device IDs <=> USB device IDs
|
||||||
std::map<s32, u64> m_ios_ids;
|
std::map<s32, u64> m_ios_ids;
|
||||||
std::map<u64, s32> m_device_ids;
|
std::map<u64, s32> m_device_ids;
|
||||||
|
|
||||||
|
ScanThread m_scan_thread{this};
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::Device
|
} // namespace IOS::HLE::Device
|
||||||
|
@ -22,6 +22,9 @@ USB_HIDv5::~USB_HIDv5() = default;
|
|||||||
|
|
||||||
IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
|
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);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
|
@ -27,11 +27,16 @@ private:
|
|||||||
|
|
||||||
bool ShouldAddDevice(const USB::Device& device) const override;
|
bool ShouldAddDevice(const USB::Device& device) const override;
|
||||||
bool HasInterfaceNumberInIDs() const override { return true; }
|
bool HasInterfaceNumberInIDs() const override { return true; }
|
||||||
|
|
||||||
|
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||||
|
|
||||||
struct AdditionalDeviceData
|
struct AdditionalDeviceData
|
||||||
{
|
{
|
||||||
u8 interrupt_in_endpoint = 0;
|
u8 interrupt_in_endpoint = 0;
|
||||||
u8 interrupt_out_endpoint = 0;
|
u8 interrupt_out_endpoint = 0;
|
||||||
};
|
};
|
||||||
std::array<AdditionalDeviceData, 32> m_additional_device_data{};
|
std::array<AdditionalDeviceData, 32> m_additional_device_data{};
|
||||||
|
|
||||||
|
ScanThread m_scan_thread{this};
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::Device
|
} // namespace IOS::HLE::Device
|
||||||
|
@ -22,6 +22,9 @@ USB_VEN::~USB_VEN() = default;
|
|||||||
|
|
||||||
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
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);
|
request.Log(GetDeviceName(), Common::Log::IOS_USB);
|
||||||
switch (request.request)
|
switch (request.request)
|
||||||
{
|
{
|
||||||
|
@ -26,5 +26,9 @@ private:
|
|||||||
|
|
||||||
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv);
|
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv);
|
||||||
bool HasInterfaceNumberInIDs() const override { return false; }
|
bool HasInterfaceNumberInIDs() const override { return false; }
|
||||||
|
|
||||||
|
ScanThread& GetScanThread() override { return m_scan_thread; }
|
||||||
|
|
||||||
|
ScanThread m_scan_thread{this};
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::Device
|
} // namespace IOS::HLE::Device
|
||||||
|
Loading…
x
Reference in New Issue
Block a user