Commit b51c982d authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

winebus.sys: Process quirky DS4 bluetooth reports.

Based on a Proton patch from Andrew Eikum <aeikum@codeweavers.com>. Signed-off-by: 's avatarRémi Bernon <rbernon@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 2369cdc1
...@@ -120,9 +120,12 @@ static inline struct base_device *impl_from_unix_device(struct unix_device *ifac ...@@ -120,9 +120,12 @@ static inline struct base_device *impl_from_unix_device(struct unix_device *ifac
return CONTAINING_RECORD(iface, struct base_device, unix_device); return CONTAINING_RECORD(iface, struct base_device, unix_device);
} }
#define QUIRK_DS4_BT 0x1
struct hidraw_device struct hidraw_device
{ {
struct base_device base; struct base_device base;
DWORD quirks;
}; };
static inline struct hidraw_device *hidraw_impl_from_unix_device(struct unix_device *iface) static inline struct hidraw_device *hidraw_impl_from_unix_device(struct unix_device *iface)
...@@ -282,7 +285,7 @@ static NTSTATUS hidraw_device_get_report_descriptor(struct unix_device *iface, B ...@@ -282,7 +285,7 @@ static NTSTATUS hidraw_device_get_report_descriptor(struct unix_device *iface, B
static void hidraw_device_read_report(struct unix_device *iface) static void hidraw_device_read_report(struct unix_device *iface)
{ {
struct hidraw_device *impl = hidraw_impl_from_unix_device(iface); struct hidraw_device *impl = hidraw_impl_from_unix_device(iface);
BYTE report_buffer[1024]; BYTE report_buffer[1024], *buff = report_buffer;
int size = read(impl->base.device_fd, report_buffer, sizeof(report_buffer)); int size = read(impl->base.device_fd, report_buffer, sizeof(report_buffer));
if (size == -1) if (size == -1)
...@@ -290,7 +293,26 @@ static void hidraw_device_read_report(struct unix_device *iface) ...@@ -290,7 +293,26 @@ static void hidraw_device_read_report(struct unix_device *iface)
else if (size == 0) else if (size == 0)
TRACE_(hid_report)("Failed to read report\n"); TRACE_(hid_report)("Failed to read report\n");
else else
bus_event_queue_input_report(&event_queue, iface, report_buffer, size); {
/* As described in the Linux kernel driver, when connected over bluetooth, DS4 controllers
* start sending input through report #17 as soon as they receive a feature report #2, which
* the kernel sends anyway for calibration.
*
* Input report #17 is the same as the default input report #1, with additional gyro data and
* two additional bytes in front, but is only described as vendor specific in the report descriptor,
* and applications aren't expecting it.
*
* We have to translate it to input report #1, like native driver does.
*/
if ((impl->quirks & QUIRK_DS4_BT) && report_buffer[0] == 0x11 && size >= 12)
{
size = 10;
buff += 2;
buff[0] = 1;
}
bus_event_queue_input_report(&event_queue, iface, buff, size);
}
} }
static void hidraw_device_set_output_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io) static void hidraw_device_set_output_report(struct unix_device *iface, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
...@@ -1149,6 +1171,12 @@ static void get_device_subsystem_info(struct udev_device *dev, char const *subsy ...@@ -1149,6 +1171,12 @@ static void get_device_subsystem_info(struct udev_device *dev, char const *subsy
ntdll_umbstowcs(tmp, strlen(tmp) + 1, desc->serialnumber, ARRAY_SIZE(desc->serialnumber)); ntdll_umbstowcs(tmp, strlen(tmp) + 1, desc->serialnumber, ARRAY_SIZE(desc->serialnumber));
} }
static void hidraw_set_quirks(struct hidraw_device *impl, DWORD bus_type, WORD vid, WORD pid)
{
if (bus_type == BUS_BLUETOOTH && is_dualshock4_gamepad(vid, pid))
impl->quirks |= QUIRK_DS4_BT;
}
static void udev_add_device(struct udev_device *dev) static void udev_add_device(struct udev_device *dev)
{ {
struct device_desc desc = struct device_desc desc =
...@@ -1250,6 +1278,7 @@ static void udev_add_device(struct udev_device *dev) ...@@ -1250,6 +1278,7 @@ static void udev_add_device(struct udev_device *dev)
impl->read_report = hidraw_device_read_report; impl->read_report = hidraw_device_read_report;
impl->udev_device = udev_device_ref(dev); impl->udev_device = udev_device_ref(dev);
impl->device_fd = fd; impl->device_fd = fd;
hidraw_set_quirks((struct hidraw_device *)impl, bus, desc.vid, desc.pid);
bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc); bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc);
} }
......
...@@ -244,5 +244,6 @@ extern BOOL hid_device_sync_report(struct unix_device *iface) DECLSPEC_HIDDEN; ...@@ -244,5 +244,6 @@ extern BOOL hid_device_sync_report(struct unix_device *iface) DECLSPEC_HIDDEN;
extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN;
BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN;
BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN;
#endif /* __WINEBUS_UNIX_PRIVATE_H */ #endif /* __WINEBUS_UNIX_PRIVATE_H */
...@@ -61,6 +61,15 @@ BOOL is_xbox_gamepad(WORD vid, WORD pid) ...@@ -61,6 +61,15 @@ BOOL is_xbox_gamepad(WORD vid, WORD pid)
return FALSE; return FALSE;
} }
BOOL is_dualshock4_gamepad(WORD vid, WORD pid)
{
if (vid != 0x054c) return FALSE;
if (pid == 0x05c4) return TRUE; /* DualShock 4 [CUH-ZCT1x] */
if (pid == 0x09cc) return TRUE; /* DualShock 4 [CUH-ZCT2x] */
if (pid == 0x0ba0) return TRUE; /* Dualshock 4 Wireless Adaptor */
return FALSE;
}
struct mouse_device struct mouse_device
{ {
struct unix_device unix_device; struct unix_device unix_device;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment