Skip to content

Commit e36f55e

Browse files
committed
input/macOs: call hid_enumerate on the main thread
1 parent 819d3dc commit e36f55e

File tree

2 files changed

+62
-29
lines changed

2 files changed

+62
-29
lines changed

rpcs3/Input/hid_pad_handler.cpp

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,19 @@ struct hid_instance
6161

6262
hid_log.notice("Initializing HIDAPI ...");
6363

64-
if (int errorCode = hid_init(); errorCode != 0)
64+
#if defined(__APPLE__)
65+
int error_code = 0;
66+
Emu.BlockingCallFromMainThread([&error_code]()
67+
{
68+
error_code = hid_init();
69+
hid_darwin_set_open_exclusive(0);
70+
});
71+
#else
72+
const int error_code = hid_init();
73+
#endif
74+
if (error_code != 0)
6575
{
66-
hid_log.fatal("hid_init error %d: %s", errorCode, hid_error(nullptr));
76+
hid_log.fatal("hid_init error %d: %s", error_code, hid_error(nullptr));
6777
return false;
6878
}
6979

@@ -92,6 +102,11 @@ void HidDevice::close()
92102
#endif
93103
}
94104

105+
#if defined(__APPLE__)
106+
template <class Device>
107+
std::mutex hid_pad_handler<Device>::s_hid_mutex;
108+
#endif
109+
95110
template <class Device>
96111
hid_pad_handler<Device>::hid_pad_handler(pad_handler type, std::vector<id_pair> ids)
97112
: PadHandlerBase(type), m_ids(std::move(ids))
@@ -104,6 +119,10 @@ hid_pad_handler<Device>::~hid_pad_handler()
104119
// Join thread
105120
m_enumeration_thread.reset();
106121

122+
#if defined(__APPLE__)
123+
std::lock_guard static_lock(s_hid_mutex);
124+
#endif
125+
107126
for (auto& controller : m_controllers)
108127
{
109128
if (controller.second)
@@ -122,10 +141,6 @@ bool hid_pad_handler<Device>::Init()
122141
if (!hid_instance::get_instance().initialize())
123142
return false;
124143

125-
#if defined(__APPLE__)
126-
hid_darwin_set_open_exclusive(0);
127-
#endif
128-
129144
for (usz i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI
130145
{
131146
m_controllers.emplace(m_name_string + std::to_string(i), std::make_shared<Device>());
@@ -186,9 +201,9 @@ void hid_pad_handler<Device>::enumerate_devices()
186201
#ifdef ANDROID
187202
{
188203
std::lock_guard lock(g_android_usb_devices_mutex);
189-
for (auto device : g_android_usb_devices)
204+
for (const android_usb_device& device : g_android_usb_devices)
190205
{
191-
auto filter = [&](id_pair id)
206+
const auto filter = [&](id_pair id)
192207
{
193208
return id.m_vid == device.vendorId && id.m_pid == device.productId;
194209
};
@@ -202,38 +217,40 @@ void hid_pad_handler<Device>::enumerate_devices()
202217
#else
203218
for (const auto& [vid, pid] : m_ids)
204219
{
205-
hid_device_info* dev_info = hid_enumerate(vid, pid);
206-
hid_device_info* head = dev_info;
207-
while (dev_info)
220+
#if defined(__APPLE__)
221+
// Let's make sure hid_enumerate is only done one thread at a time
222+
std::lock_guard static_lock(s_hid_mutex);
223+
Emu.BlockingCallFromMainThread([&]()
224+
{
225+
#endif
226+
hid_device_info* head = hid_enumerate(vid, pid);
227+
for (hid_device_info* dev_info = head; dev_info != nullptr; dev_info = dev_info->next)
208228
{
209229
if (!dev_info->path)
210230
{
211231
hid_log.error("Skipping enumeration of device with empty path.");
212232
continue;
213233
}
214234

215-
const std::string path = dev_info->path;
235+
std::string path = dev_info->path;
216236
device_paths.insert(path);
217237

218238
#ifdef _WIN32
219239
// Only add serials for col01 ps move device
220240
if (m_type == pad_handler::move && path.find("&Col01#") != umax)
221241
#endif
222242
{
223-
serials[path] = dev_info->serial_number ? std::wstring(dev_info->serial_number) : std::wstring();
243+
serials[std::move(path)] = dev_info->serial_number ? std::wstring(dev_info->serial_number) : std::wstring();
224244
}
225-
226-
dev_info = dev_info->next;
227245
}
228246
hid_free_enumeration(head);
247+
#if defined(__APPLE__)
248+
});
249+
#endif
229250
}
230251
#endif
231252
hid_log.notice("%s enumeration found %d devices (%f ms)", m_type, device_paths.size(), timer.GetElapsedTimeInMilliSec());
232253

233-
std::lock_guard lock(m_enumeration_mutex);
234-
m_new_enumerated_devices = device_paths;
235-
m_enumerated_serials = std::move(serials);
236-
237254
#ifdef _WIN32
238255
if (m_type == pad_handler::move)
239256
{
@@ -243,7 +260,7 @@ void hid_pad_handler<Device>::enumerate_devices()
243260
// Filter paths. We only want the Col01 paths.
244261
std::set<std::string> col01_paths;
245262

246-
for (const std::string& path : m_new_enumerated_devices)
263+
for (const std::string& path : device_paths)
247264
{
248265
hid_log.trace("Found ps move device: %s", path);
249266

@@ -253,27 +270,38 @@ void hid_pad_handler<Device>::enumerate_devices()
253270
}
254271
}
255272

256-
m_new_enumerated_devices = std::move(col01_paths);
273+
device_paths = std::move(col01_paths);
257274
}
258275
#endif
276+
277+
std::lock_guard lock(m_enumeration_mutex);
278+
m_new_enumerated_devices = std::move(device_paths);
279+
m_new_enumerated_serials = std::move(serials);
259280
}
260281

261282
template <class Device>
262283
void hid_pad_handler<Device>::update_devices()
263284
{
264-
std::lock_guard lock(m_enumeration_mutex);
265-
266-
if (m_last_enumerated_devices == m_new_enumerated_devices)
267285
{
268-
return;
286+
std::lock_guard lock(m_enumeration_mutex);
287+
288+
if (m_enumerated_devices == m_new_enumerated_devices)
289+
{
290+
return;
291+
}
292+
293+
m_enumerated_devices = std::move(m_new_enumerated_devices);
294+
m_enumerated_serials = std::move(m_new_enumerated_serials);
269295
}
270296

271-
m_last_enumerated_devices = m_new_enumerated_devices;
297+
#if defined(__APPLE__)
298+
std::lock_guard static_lock(s_hid_mutex);
299+
#endif
272300

273301
// Scrap devices that are not in the new list
274302
for (auto& controller : m_controllers)
275303
{
276-
if (controller.second && controller.second->path != hid_enumerated_device_default && !m_new_enumerated_devices.contains(controller.second->path))
304+
if (controller.second && controller.second->path != hid_enumerated_device_default && !m_enumerated_devices.contains(controller.second->path))
277305
{
278306
controller.second->close();
279307
cfg_pad* config = controller.second->config;
@@ -285,7 +313,7 @@ void hid_pad_handler<Device>::update_devices()
285313
bool warn_about_drivers = false;
286314

287315
// Find and add new devices
288-
for (const auto& path : m_new_enumerated_devices)
316+
for (const auto& path : m_enumerated_devices)
289317
{
290318
// Check if we have at least one virtual controller left
291319
if (std::none_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; }))

rpcs3/Input/hid_pad_handler.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,17 @@ class hid_pad_handler : public PadHandlerBase
102102
// pseudo 'controller id' to keep track of unique controllers
103103
std::map<std::string, std::shared_ptr<Device>> m_controllers;
104104

105-
std::set<hid_enumerated_device_type> m_last_enumerated_devices;
105+
std::set<hid_enumerated_device_type> m_enumerated_devices;
106106
std::set<hid_enumerated_device_type> m_new_enumerated_devices;
107107
std::map<hid_enumerated_device_type, std::wstring> m_enumerated_serials;
108+
std::map<hid_enumerated_device_type, std::wstring> m_new_enumerated_serials;
108109
std::mutex m_enumeration_mutex;
109110
std::unique_ptr<named_thread<std::function<void()>>> m_enumeration_thread;
110111

112+
#if defined(__APPLE__)
113+
static std::mutex s_hid_mutex;
114+
#endif
115+
111116
void enumerate_devices();
112117
void update_devices();
113118
std::shared_ptr<Device> get_hid_device(const std::string& padId);

0 commit comments

Comments
 (0)