mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-10-12 02:09:17 +00:00
LogitechG27: mirror mapped steering device presence on the usb bus
The emulated G27 was always attached while enabled, so games kept reading a phantom wheel (centered steering after the previous commit, formerly hard-left) and ignored pad steering input. Attach the emulated device only while the mapped steering device is connected: games now see the wheel plug in and out exactly like on real hardware, and pad play works without disabling the option and restarting the game. Also guard the personality reconnect against the device having been detached between the game's mode-change request and the housekeeping tick. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
committed by
Megamouse
co-authored by
Claude Fable 5
parent
b7056bc88a
commit
1b3e02044f
@@ -147,6 +147,7 @@ public:
|
||||
void connect_usb_device(std::shared_ptr<usb_device> dev, bool update_usb_devices = false);
|
||||
void disconnect_usb_device(std::shared_ptr<usb_device> dev, bool update_usb_devices = false);
|
||||
void reconnect_usb_device(u32 assigned_number);
|
||||
void set_usb_device_attached(usb_device* raw_dev, bool attached);
|
||||
|
||||
// Map of devices actively handled by the ps3(device_id, device)
|
||||
std::map<u32, std::pair<UsbInternalDevice, std::shared_ptr<usb_device>>> handled_devices;
|
||||
@@ -962,6 +963,12 @@ void usb_handler_thread::connect_usb_device(std::shared_ptr<usb_device> dev, boo
|
||||
if (update_usb_devices)
|
||||
usb_devices.push_back(dev);
|
||||
|
||||
if (!dev->is_attachable())
|
||||
{
|
||||
sys_usbd.trace("USB device(VID=0x%04x, PID=0x%04x) is not attachable, skipping connection", dev->device._device.idVendor, dev->device._device.idProduct);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& [name, ldd] : ldds)
|
||||
{
|
||||
if (dev->device._device.idVendor == ldd.id_vendor && dev->device._device.idProduct >= ldd.id_product_min && dev->device._device.idProduct <= ldd.id_product_max)
|
||||
@@ -1019,6 +1026,23 @@ void usb_handler_thread::reconnect_usb_device(u32 assigned_number)
|
||||
}
|
||||
}
|
||||
|
||||
void usb_handler_thread::set_usb_device_attached(usb_device* raw_dev, bool attached)
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
for (const auto& dev : usb_devices)
|
||||
{
|
||||
if (dev.get() != raw_dev)
|
||||
continue;
|
||||
|
||||
if (attached && !dev->assigned_number)
|
||||
connect_usb_device(dev, false);
|
||||
else if (!attached && dev->assigned_number)
|
||||
disconnect_usb_device(dev, false);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void connect_usb_controller(u8 index, input::product_type type)
|
||||
{
|
||||
auto usbh = g_fxo->try_get<named_thread<usb_handler_thread>>();
|
||||
@@ -1115,6 +1139,16 @@ void reconnect_usb(u32 assigned_number)
|
||||
usbh->reconnect_usb_device(assigned_number);
|
||||
}
|
||||
|
||||
void set_usb_device_attached(usb_device* dev, bool attached)
|
||||
{
|
||||
auto usbh = g_fxo->try_get<named_thread<usb_handler_thread>>();
|
||||
if (!usbh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
usbh->set_usb_device_attached(dev, attached);
|
||||
}
|
||||
|
||||
void handle_hotplug_event(bool connected, bool source_is_libusb)
|
||||
{
|
||||
if (auto usbh = g_fxo->try_get<named_thread<usb_handler_thread>>())
|
||||
|
||||
@@ -88,6 +88,9 @@ error_code sys_usbd_get_device_speed(ppu_thread& ppu);
|
||||
error_code sys_usbd_register_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product, u16 id_vendor, u16 id_product_min, u16 id_product_max);
|
||||
error_code sys_usbd_unregister_extra_ldd(ppu_thread& ppu, u32 handle, vm::cptr<char> s_product, u16 slen_product);
|
||||
|
||||
class usb_device;
|
||||
|
||||
void connect_usb_controller(u8 index, input::product_type);
|
||||
void reconnect_usb(u32 assigned_number);
|
||||
void set_usb_device_attached(usb_device* dev, bool attached);
|
||||
void handle_hotplug_event(bool connected, bool source_is_libusb);
|
||||
|
||||
@@ -303,8 +303,10 @@ void usb_device_logitech_g27::set_personality(logitech_personality personality,
|
||||
index += raw_config[index];
|
||||
}
|
||||
|
||||
if (reconnect)
|
||||
if (reconnect && assigned_number)
|
||||
{
|
||||
// assigned_number can be 0 if the device was detached (mapped steering device unplugged)
|
||||
// after the game requested the personality change
|
||||
reconnect_usb(assigned_number);
|
||||
}
|
||||
}
|
||||
@@ -332,11 +334,30 @@ usb_device_logitech_g27::usb_device_logitech_g27(u32 controller_index, const std
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
// Initial refresh before the usb handler connects the device, so is_attachable() already reflects the physical state
|
||||
sdl_refresh();
|
||||
|
||||
m_house_keeping_thread = std::make_unique<named_thread<std::function<void()>>>("Logitech G27", [this]()
|
||||
{
|
||||
bool last_steering_device_present = m_steering_device_present;
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
// Pump SDL events here as well: while the device is detached no interrupt transfers run,
|
||||
// so this is the only pump that lets SDL notice the wheel being plugged back in
|
||||
sdl_instance::get_instance().pump_events();
|
||||
|
||||
sdl_refresh();
|
||||
|
||||
// Mirror the physical presence of the mapped steering device on the emulated usb bus, so games
|
||||
// fall back to the pad when the real wheel is not connected instead of reading a phantom wheel
|
||||
const bool steering_device_present = m_steering_device_present;
|
||||
if (steering_device_present != last_steering_device_present)
|
||||
{
|
||||
set_usb_device_attached(this, steering_device_present);
|
||||
last_steering_device_present = steering_device_present;
|
||||
}
|
||||
|
||||
thread_ctrl::wait_for(1'000'000);
|
||||
|
||||
std::unique_lock lock(g_cfg_logitech_g27.m_mutex);
|
||||
@@ -354,6 +375,11 @@ bool usb_device_logitech_g27::open_device()
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
bool usb_device_logitech_g27::is_attachable() const
|
||||
{
|
||||
return m_enabled && m_steering_device_present;
|
||||
}
|
||||
|
||||
static void clear_sdl_joysticks(std::map<u64, std::vector<SDL_Joystick*>>& joystick_map)
|
||||
{
|
||||
for (auto& [type, joysticks] : joystick_map)
|
||||
@@ -612,6 +638,13 @@ void usb_device_logitech_g27::sdl_refresh()
|
||||
if (new_haptic_handle)
|
||||
SDL_CloseHaptic(new_haptic_handle);
|
||||
}
|
||||
|
||||
{
|
||||
// Cache the presence of the mapped steering device for is_attachable()
|
||||
const std::lock_guard<std::mutex> handles_lock(m_sdl_handles_mutex);
|
||||
const auto steering_joysticks = m_joysticks.find(m_mapping.steering.device_type_id);
|
||||
m_steering_device_present = steering_joysticks != m_joysticks.end() && !steering_joysticks->second.empty();
|
||||
}
|
||||
}
|
||||
|
||||
static inline s16 logitech_g27_force_to_level(u8 force, bool reverse = false)
|
||||
|
||||
@@ -117,6 +117,7 @@ public:
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||
bool open_device() override;
|
||||
bool is_attachable() const override;
|
||||
|
||||
private:
|
||||
void sdl_refresh();
|
||||
@@ -149,5 +150,8 @@ private:
|
||||
|
||||
bool m_enabled = false;
|
||||
|
||||
// Updated by sdl_refresh, read by is_attachable which cannot take m_sdl_handles_mutex (called from the usb handler)
|
||||
atomic_t<bool> m_steering_device_present = false;
|
||||
|
||||
std::unique_ptr<named_thread<std::function<void()>>> m_house_keeping_thread;
|
||||
};
|
||||
|
||||
@@ -226,6 +226,12 @@ public:
|
||||
|
||||
virtual bool open_device() = 0;
|
||||
|
||||
// Emulated devices can decline attachment to the bus, e.g. while the real hardware they are backed by is not connected
|
||||
virtual bool is_attachable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_location(u8* location) const;
|
||||
virtual void read_descriptors();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user