Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winexinput.sys/main.c | 68 ++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 7 deletions(-)
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index 60f7a8ed5dd..330c9203b7d 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -82,6 +82,14 @@ struct func_device
WCHAR instance_id[MAX_DEVICE_ID_LEN];
+ HIDP_VALUE_CAPS lx_caps; + HIDP_VALUE_CAPS ly_caps; + HIDP_VALUE_CAPS lt_caps; + HIDP_VALUE_CAPS rx_caps; + HIDP_VALUE_CAPS ry_caps; + HIDP_VALUE_CAPS rt_caps; + HIDP_DEVICE_DESC device_desc; + /* everything below requires holding the cs */ CRITICAL_SECTION cs; ULONG report_len; @@ -442,13 +450,27 @@ static NTSTATUS sync_ioctl(DEVICE_OBJECT *device, DWORD code, void *in_buf, DWOR return io.Status; }
+static void check_value_caps(struct func_device *fdo, USHORT usage, HIDP_VALUE_CAPS *caps) +{ + switch (usage) + { + case HID_USAGE_GENERIC_X: fdo->lx_caps = *caps; break; + case HID_USAGE_GENERIC_Y: fdo->ly_caps = *caps; break; + case HID_USAGE_GENERIC_Z: fdo->lt_caps = *caps; break; + case HID_USAGE_GENERIC_RX: fdo->rx_caps = *caps; break; + case HID_USAGE_GENERIC_RY: fdo->ry_caps = *caps; break; + case HID_USAGE_GENERIC_RZ: fdo->rt_caps = *caps; break; + } +} + static NTSTATUS initialize_device(DEVICE_OBJECT *device) { struct func_device *fdo = fdo_from_DEVICE_OBJECT(device); - ULONG i, report_desc_len, report_count; + ULONG i, u, button_count, report_desc_len, report_count; PHIDP_REPORT_DESCRIPTOR report_desc; PHIDP_PREPARSED_DATA preparsed; - HIDP_DEVICE_DESC device_desc; + HIDP_BUTTON_CAPS *button_caps; + HIDP_VALUE_CAPS *value_caps; HIDP_REPORT_IDS *reports; HID_DESCRIPTOR hid_desc; NTSTATUS status; @@ -461,16 +483,48 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device) if (!(report_desc = malloc(report_desc_len))) return STATUS_NO_MEMORY;
status = sync_ioctl(fdo->bus_device, IOCTL_HID_GET_REPORT_DESCRIPTOR, NULL, 0, report_desc, report_desc_len); - if (!status) status = HidP_GetCollectionDescription(report_desc, report_desc_len, PagedPool, &device_desc); + if (!status) status = HidP_GetCollectionDescription(report_desc, report_desc_len, PagedPool, &fdo->device_desc); free(report_desc); if (status != HIDP_STATUS_SUCCESS) return status;
- preparsed = device_desc.CollectionDesc->PreparsedData; + preparsed = fdo->device_desc.CollectionDesc->PreparsedData; status = HidP_GetCaps(preparsed, &caps); if (status != HIDP_STATUS_SUCCESS) return status;
- reports = device_desc.ReportIDs; - report_count = device_desc.ReportIDsLength; + button_count = 0; + if (!(button_caps = malloc(sizeof(*button_caps) * caps.NumberInputButtonCaps))) return STATUS_NO_MEMORY; + status = HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, preparsed); + if (status != HIDP_STATUS_SUCCESS) return status; + else for (i = 0; i < caps.NumberInputButtonCaps; i++) + { + if (button_caps[i].UsagePage != HID_USAGE_PAGE_BUTTON) continue; + if (button_caps[i].IsRange) button_count = max(button_count, button_caps[i].Range.UsageMax); + else button_count = max(button_count, button_caps[i].NotRange.Usage); + } + free(button_caps); + if (button_count < 10) WARN("only %u buttons found\n", button_count); + + if (!(value_caps = malloc(sizeof(*value_caps) * caps.NumberInputValueCaps))) return STATUS_NO_MEMORY; + status = HidP_GetValueCaps(HidP_Input, value_caps, &caps.NumberInputValueCaps, preparsed); + if (status != HIDP_STATUS_SUCCESS) return status; + else for (i = 0; i < caps.NumberInputValueCaps; i++) + { + HIDP_VALUE_CAPS *caps = value_caps + i; + if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) continue; + if (!caps->IsRange) check_value_caps(fdo, caps->NotRange.Usage, caps); + else for (u = caps->Range.UsageMin; u <=caps->Range.UsageMax; u++) check_value_caps(fdo, u, value_caps + i); + } + free(value_caps); + + if (!fdo->lx_caps.UsagePage) WARN("missing lx axis\n"); + if (!fdo->ly_caps.UsagePage) WARN("missing ly axis\n"); + if (!fdo->lt_caps.UsagePage) WARN("missing lt axis\n"); + if (!fdo->rx_caps.UsagePage) WARN("missing rx axis\n"); + if (!fdo->ry_caps.UsagePage) WARN("missing ry axis\n"); + if (!fdo->rt_caps.UsagePage) WARN("missing rt axis\n"); + + reports = fdo->device_desc.ReportIDs; + report_count = fdo->device_desc.ReportIDsLength; for (i = 0; i < report_count; ++i) if (!reports[i].ReportID || reports[i].InputLength) break; if (i == report_count) i = 0; /* no input report?!, just use first ID */
@@ -478,7 +532,6 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device) if (!(fdo->report_buf = malloc(fdo->report_len))) return STATUS_NO_MEMORY; fdo->report_buf[0] = reports[i].ReportID;
- HidP_FreeCollectionDescription(&device_desc); return STATUS_SUCCESS; }
@@ -556,6 +609,7 @@ static NTSTATUS WINAPI fdo_pnp(DEVICE_OBJECT *device, IRP *irp) status = IoCallDriver(fdo->bus_device, irp); IoDetachDevice(fdo->bus_device); RtlDeleteCriticalSection(&fdo->cs); + HidP_FreeCollectionDescription(&fdo->device_desc); free(fdo->report_buf); IoDeleteDevice(device); return status;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winexinput.sys/main.c | 188 ++++++++++++++++++++++++++- dlls/winexinput.sys/pop_hid_macros.h | 83 ++++++++++++ dlls/winexinput.sys/psh_hid_macros.h | 85 ++++++++++++ dlls/xinput1_3/tests/xinput.c | 25 ---- 4 files changed, 349 insertions(+), 32 deletions(-) create mode 100644 dlls/winexinput.sys/pop_hid_macros.h create mode 100644 dlls/winexinput.sys/psh_hid_macros.h
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index 330c9203b7d..724552cfcac 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -50,6 +50,75 @@ __ASM_STDCALL_FUNC(wrap_fastcall_func1, 8, #define call_fastcall_func1(func,a) func(a) #endif
+#include "psh_hid_macros.h" + +const BYTE xinput_report_desc[] = +{ + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_GAMEPAD), + COLLECTION(1, Application), + USAGE(1, 0), + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MAXIMUM(2, 0xffff), + PHYSICAL_MAXIMUM(2, 0xffff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_RX), + USAGE(1, HID_USAGE_GENERIC_RY), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + COLLECTION(1, Physical), + USAGE(1, HID_USAGE_GENERIC_Z), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 10), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 1), + REPORT_COUNT(1, 10), + REPORT_SIZE(1, 1), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MAXIMUM(2, 0x103b), + REPORT_SIZE(1, 4), + REPORT_COUNT(4, 1), + UNIT(1, 0x0e /* none */), + INPUT(1, Data|Var|Abs|Null), + + REPORT_COUNT(1, 18), + REPORT_SIZE(1, 1), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, +}; + +#include "pop_hid_macros.h" + +struct xinput_state +{ + WORD lx_axis; + WORD ly_axis; + WORD rx_axis; + WORD ry_axis; + WORD trigger; + WORD buttons; + WORD padding; +}; + struct device { BOOL is_fdo; @@ -96,6 +165,7 @@ struct func_device char *report_buf; IRP *pending_read; BOOL pending_is_gamepad; + struct xinput_state xinput_state; };
static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device) @@ -105,6 +175,73 @@ static inline struct func_device *fdo_from_DEVICE_OBJECT(DEVICE_OBJECT *device) else return CONTAINING_RECORD(impl, struct phys_device, base)->fdo; }
+static LONG sign_extend(ULONG value, const HIDP_VALUE_CAPS *caps) +{ + UINT sign = 1 << (caps->BitSize - 1); + if (sign <= 1 || caps->LogicalMin >= 0) return value; + return value - ((value & sign) << 1); +} + +static LONG scale_value(ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max) +{ + LONG tmp = sign_extend(value, caps); + if (caps->LogicalMin > caps->LogicalMax) return 0; + if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return 0; + return min + MulDiv(tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin); +} + +static void translate_report_to_xinput_state(struct func_device *fdo) +{ + ULONG lx = 0, ly = 0, rx = 0, ry = 0, lt = 0, rt = 0, hat = 0; + PHIDP_PREPARSED_DATA preparsed; + USAGE usages[10]; + NTSTATUS status; + ULONG i, count; + + preparsed = fdo->device_desc.CollectionDesc->PreparsedData; + + count = ARRAY_SIZE(usages); + status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, + &count, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, + &hat, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue hat returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, + &lx, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue x returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, + &ly, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue y returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, + <, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue z returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, + &rx, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue rx returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, + &ry, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue ry returned %#x\n", status); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, + &rt, preparsed, fdo->report_buf, fdo->report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue rz returned %#x\n", status); + + if (hat < 1 || hat > 8) fdo->xinput_state.buttons = 0; + else fdo->xinput_state.buttons = hat << 10; + for (i = 0; i < count; i++) + { + if (usages[i] < 1 || usages[i] > 10) continue; + fdo->xinput_state.buttons |= (1 << (usages[i] - 1)); + } + fdo->xinput_state.lx_axis = scale_value(lx, &fdo->lx_caps, 0, 65535); + fdo->xinput_state.ly_axis = scale_value(ly, &fdo->ly_caps, 0, 65535); + fdo->xinput_state.rx_axis = scale_value(rx, &fdo->rx_caps, 0, 65535); + fdo->xinput_state.ry_axis = scale_value(ry, &fdo->ry_caps, 0, 65535); + rt = scale_value(rt, &fdo->rt_caps, 0, 255); + lt = scale_value(lt, &fdo->lt_caps, 0, 255); + fdo->xinput_state.trigger = 0x8000 + (lt - rt) * 128; +} + static NTSTATUS WINAPI read_completion(DEVICE_OBJECT *device, IRP *xinput_irp, void *context) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(xinput_irp); @@ -121,7 +258,9 @@ static NTSTATUS WINAPI read_completion(DEVICE_OBJECT *device, IRP *xinput_irp, v RtlEnterCriticalSection(&fdo->cs); offset = fdo->report_buf[0] ? 0 : 1; memcpy(fdo->report_buf + offset, read_buf, read_len); - memcpy(gamepad_irp->UserBuffer, read_buf, read_len); + translate_report_to_xinput_state(fdo); + memcpy(gamepad_irp->UserBuffer, &fdo->xinput_state, sizeof(fdo->xinput_state)); + gamepad_irp->IoStatus.Information = sizeof(fdo->xinput_state); RtlLeaveCriticalSection(&fdo->cs); }
@@ -178,6 +317,7 @@ static NTSTATUS try_complete_pending_read(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI gamepad_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + ULONG output_len = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; struct func_device *fdo = fdo_from_DEVICE_OBJECT(device);
@@ -185,20 +325,54 @@ static NTSTATUS WINAPI gamepad_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
switch (code) { - case IOCTL_HID_GET_INPUT_REPORT: + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: { - HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer; + HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR *)irp->UserBuffer;
- RtlEnterCriticalSection(&fdo->cs); - memcpy(packet->reportBuffer, fdo->report_buf, fdo->report_len); - irp->IoStatus.Information = fdo->report_len; - RtlLeaveCriticalSection(&fdo->cs); + irp->IoStatus.Information = sizeof(*descriptor); + if (output_len < sizeof(*descriptor)) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + memset(descriptor, 0, sizeof(*descriptor)); + descriptor->bLength = sizeof(*descriptor); + descriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; + descriptor->bcdHID = HID_REVISION; + descriptor->bCountry = 0; + descriptor->bNumDescriptors = 1; + descriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE; + descriptor->DescriptorList[0].wReportLength = sizeof(xinput_report_desc);
irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_SUCCESS; }
+ case IOCTL_HID_GET_REPORT_DESCRIPTOR: + irp->IoStatus.Information = sizeof(xinput_report_desc); + if (output_len < sizeof(xinput_report_desc)) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + memcpy(irp->UserBuffer, xinput_report_desc, sizeof(xinput_report_desc)); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + + case IOCTL_HID_GET_INPUT_REPORT: + case IOCTL_HID_SET_OUTPUT_REPORT: + case IOCTL_HID_GET_FEATURE: + case IOCTL_HID_SET_FEATURE: + irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + default: IoSkipCurrentIrpStackLocation(irp); return IoCallDriver(fdo->bus_device, irp); diff --git a/dlls/winexinput.sys/pop_hid_macros.h b/dlls/winexinput.sys/pop_hid_macros.h new file mode 100644 index 00000000000..767c26e8ecb --- /dev/null +++ b/dlls/winexinput.sys/pop_hid_macros.h @@ -0,0 +1,83 @@ +/* + * HID report helper macros. + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#undef Data +#undef Cnst +#undef Array +#undef Var +#undef Abs +#undef Rel +#undef NoWrap +#undef Wrap +#undef NonLin +#undef Lin +#undef NoPref +#undef Pref +#undef NoNull +#undef Null +#undef NonVol +#undef Vol +#undef Bits +#undef Buff + +#undef Physical +#undef Application +#undef Logical +#undef Report +#undef NamedArray +#undef UsageSwitch +#undef UsageModifier + +#undef SHORT_ITEM_0 +#undef SHORT_ITEM_1 +#undef SHORT_ITEM_2 +#undef SHORT_ITEM_4 + +#undef LONG_ITEM + +#undef INPUT +#undef OUTPUT +#undef FEATURE +#undef COLLECTION +#undef END_COLLECTION + +#undef USAGE_PAGE +#undef LOGICAL_MINIMUM +#undef LOGICAL_MAXIMUM +#undef PHYSICAL_MINIMUM +#undef PHYSICAL_MAXIMUM +#undef UNIT_EXPONENT +#undef UNIT +#undef REPORT_SIZE +#undef REPORT_ID +#undef REPORT_COUNT +#undef PUSH +#undef POP + +#undef USAGE +#undef USAGE_MINIMUM +#undef USAGE_MAXIMUM +#undef DESIGNATOR_INDEX +#undef DESIGNATOR_MINIMUM +#undef DESIGNATOR_MAXIMUM +#undef STRING_INDEX +#undef STRING_MINIMUM +#undef STRING_MAXIMUM +#undef DELIMITER diff --git a/dlls/winexinput.sys/psh_hid_macros.h b/dlls/winexinput.sys/psh_hid_macros.h new file mode 100644 index 00000000000..4623af20598 --- /dev/null +++ b/dlls/winexinput.sys/psh_hid_macros.h @@ -0,0 +1,85 @@ +/* + * HID report helper macros. + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <hidusage.h> + +#define Data 0 +#define Cnst 0x01 +#define Ary 0 +#define Var 0x02 +#define Abs 0 +#define Rel 0x04 +#define NoWrap 0 +#define Wrap 0x08 +#define NonLin 0 +#define Lin 0x10 +#define NoPref 0 +#define Pref 0x20 +#define NoNull 0 +#define Null 0x40 +#define NonVol 0 +#define Vol 0x80 +#define Bits 0 +#define Buff 0x100 + +#define Physical 0x00 +#define Application 0x01 +#define Logical 0x02 +#define Report 0x03 +#define NamedArray 0x04 +#define UsageSwitch 0x05 +#define UsageModifier 0x06 + +#define SHORT_ITEM_0(tag,type) (((tag)<<4)|((type)<<2)|0) +#define SHORT_ITEM_1(tag,type,data) (((tag)<<4)|((type)<<2)|1),((data)&0xff) +#define SHORT_ITEM_2(tag,type,data) (((tag)<<4)|((type)<<2)|2),((data)&0xff),(((data)>>8)&0xff) +#define SHORT_ITEM_4(tag,type,data) (((tag)<<4)|((type)<<2)|3),((data)&0xff),(((data)>>8)&0xff),(((data)>>16)&0xff),(((data)>>24)&0xff) + +#define LONG_ITEM(tag,size) SHORT_ITEM_2(0xf,0x3,((tag)<<8)|(size)) + +#define INPUT(n,data) SHORT_ITEM_##n(0x8,0,data) +#define OUTPUT(n,data) SHORT_ITEM_##n(0x9,0,data) +#define FEATURE(n,data) SHORT_ITEM_##n(0xb,0,data) +#define COLLECTION(n,data) SHORT_ITEM_##n(0xa,0,data) +#define END_COLLECTION SHORT_ITEM_0(0xc,0) + +#define USAGE_PAGE(n,data) SHORT_ITEM_##n(0x0,1,data) +#define LOGICAL_MINIMUM(n,data) SHORT_ITEM_##n(0x1,1,data) +#define LOGICAL_MAXIMUM(n,data) SHORT_ITEM_##n(0x2,1,data) +#define PHYSICAL_MINIMUM(n,data) SHORT_ITEM_##n(0x3,1,data) +#define PHYSICAL_MAXIMUM(n,data) SHORT_ITEM_##n(0x4,1,data) +#define UNIT_EXPONENT(n,data) SHORT_ITEM_##n(0x5,1,data) +#define UNIT(n,data) SHORT_ITEM_##n(0x6,1,data) +#define REPORT_SIZE(n,data) SHORT_ITEM_##n(0x7,1,data) +#define REPORT_ID(n,data) SHORT_ITEM_##n(0x8,1,data) +#define REPORT_COUNT(n,data) SHORT_ITEM_##n(0x9,1,data) +#define PUSH(n,data) SHORT_ITEM_##n(0xa,1,data) +#define POP(n,data) SHORT_ITEM_##n(0xb,1,data) + +#define USAGE(n,data) SHORT_ITEM_##n(0x0,2,data) +#define USAGE_MINIMUM(n,data) SHORT_ITEM_##n(0x1,2,data) +#define USAGE_MAXIMUM(n,data) SHORT_ITEM_##n(0x2,2,data) +#define DESIGNATOR_INDEX(n,data) SHORT_ITEM_##n(0x3,2,data) +#define DESIGNATOR_MINIMUM(n,data) SHORT_ITEM_##n(0x4,2,data) +#define DESIGNATOR_MAXIMUM(n,data) SHORT_ITEM_##n(0x5,2,data) +#define STRING_INDEX(n,data) SHORT_ITEM_##n(0x6,2,data) +#define STRING_MINIMUM(n,data) SHORT_ITEM_##n(0x7,2,data) +#define STRING_MAXIMUM(n,data) SHORT_ITEM_##n(0x8,2,data) +#define DELIMITER(n,data) SHORT_ITEM_##n(0x9,2,data) diff --git a/dlls/xinput1_3/tests/xinput.c b/dlls/xinput1_3/tests/xinput.c index 811fe045d10..60c5817c79a 100644 --- a/dlls/xinput1_3/tests/xinput.c +++ b/dlls/xinput1_3/tests/xinput.c @@ -455,21 +455,15 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre
check_member(*hid_caps, expect_hid_caps, "%04x", Usage); check_member(*hid_caps, expect_hid_caps, "%04x", UsagePage); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", InputReportByteLength); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", OutputReportByteLength); check_member(*hid_caps, expect_hid_caps, "%d", FeatureReportByteLength); check_member(*hid_caps, expect_hid_caps, "%d", NumberLinkCollectionNodes); check_member(*hid_caps, expect_hid_caps, "%d", NumberInputButtonCaps); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", NumberInputValueCaps); - todo_wine check_member(*hid_caps, expect_hid_caps, "%d", NumberInputDataIndices); check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputButtonCaps); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputValueCaps); - todo_wine_if(xi_caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) check_member(*hid_caps, expect_hid_caps, "%d", NumberOutputDataIndices); check_member(*hid_caps, expect_hid_caps, "%d", NumberFeatureButtonCaps); check_member(*hid_caps, expect_hid_caps, "%d", NumberFeatureValueCaps); @@ -522,11 +516,8 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre else if (button_caps[i].IsRange && expect_button_caps[i].IsRange) { check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMin); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMax); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMin); - todo_wine check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMax); }
@@ -551,7 +542,6 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre count = hid_caps->NumberInputValueCaps; status = HidP_GetValueCaps(HidP_Input, value_caps, &count, preparsed); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetValueCaps returned %#x\n", status); - todo_wine ok(count == ARRAY_SIZE(expect_value_caps), "got %d value caps\n", count);
for (i = 0; i < min(count, ARRAY_SIZE(expect_value_caps)); ++i) @@ -560,11 +550,8 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre check_member(value_caps[i], expect_value_caps[i], "%04x", UsagePage); check_member(value_caps[i], expect_value_caps[i], "%d", ReportID); check_member(value_caps[i], expect_value_caps[i], "%d", IsAlias); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", BitField); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LinkCollection); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LinkUsage); check_member(value_caps[i], expect_value_caps[i], "%d", LinkUsagePage); check_member(value_caps[i], expect_value_caps[i], "%d", IsRange); @@ -572,27 +559,19 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre check_member(value_caps[i], expect_value_caps[i], "%d", IsDesignatorRange); check_member(value_caps[i], expect_value_caps[i], "%d", IsAbsolute);
- todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", HasNull); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", BitSize); check_member(value_caps[i], expect_value_caps[i], "%d", ReportCount); check_member(value_caps[i], expect_value_caps[i], "%d", UnitsExp); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", Units); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", LogicalMin); - todo_wine check_member(value_caps[i], expect_value_caps[i], "%d", LogicalMax); check_member(value_caps[i], expect_value_caps[i], "%d", PhysicalMin); - todo_wine check_member(value_caps[i], expect_value_caps[i], "%d", PhysicalMax);
if (!value_caps[i].IsRange && !expect_value_caps[i].IsRange) { - todo_wine_if(i >= 4) check_member(value_caps[i], expect_value_caps[i], "%04x", NotRange.Usage); - todo_wine_if(i == 5) check_member(value_caps[i], expect_value_caps[i], "%d", NotRange.DataIndex); } else if (value_caps[i].IsRange && expect_value_caps[i].IsRange) @@ -627,9 +606,7 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre SetLastError(0xdeadbeef); memset(buffer, 0, sizeof(buffer)); ret = HidD_GetInputReport(device, buffer, hid_caps->InputReportByteLength); - todo_wine ok(!ret, "HidD_GetInputReport succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "HidD_GetInputReport returned error %u\n", GetLastError());
if (!winetest_interactive) skip("skipping interactive tests\n"); @@ -737,12 +714,10 @@ static void check_hid_caps(DWORD index, HANDLE device, PHIDP_PREPARSED_DATA pre value = 0; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, preparsed, buffer, hid_caps->InputReportByteLength); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status); - todo_wine ok(value == 32768 + (state.Gamepad.bLeftTrigger - state.Gamepad.bRightTrigger) * 128, "got Z value %d (RT %d, LT %d)\n", value, state.Gamepad.bRightTrigger, state.Gamepad.bLeftTrigger); value = 0; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, preparsed, buffer, hid_caps->InputReportByteLength); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetUsageValue returned %#x\n", status); } while (ret && (state.Gamepad.bRightTrigger != 255 || state.Gamepad.bLeftTrigger != 255)); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winexinput.sys/winexinput.inf | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/winexinput.sys/winexinput.inf b/dlls/winexinput.sys/winexinput.inf index 2f388c190ca..b20d4c08125 100644 --- a/dlls/winexinput.sys/winexinput.inf +++ b/dlls/winexinput.sys/winexinput.inf @@ -8,6 +8,32 @@ Wine=mfg_section
[mfg_section] Wine XInput compatible device=device_section,WINEBUS\WINE_COMP_XINPUT +Xbox Controller=device_section,WINEBUS\VID_045E&PID_0202 +Xbox Controller=device_section,WINEBUS\VID_045E&PID_0202&MI_00 +Xbox Controller S=device_section,WINEBUS\VID_045E&PID_0285 +Xbox Controller S=device_section,WINEBUS\VID_045E&PID_0285&MI_00 +Xbox Controller S=device_section,WINEBUS\VID_045E&PID_0289 +Xbox Controller S=device_section,WINEBUS\VID_045E&PID_0289&MI_00 +Xbox360 Controller=device_section,WINEBUS\VID_045E&PID_028E +Xbox360 Controller=device_section,WINEBUS\VID_045E&PID_028E&MI_00 +Xbox360 Wireless Controller=device_section,WINEBUS\VID_045E&PID_028F +Xbox360 Wireless Controller=device_section,WINEBUS\VID_045E&PID_028F&MI_00 +Xbox One Controller=device_section,WINEBUS\VID_045E&PID_02D1 +Xbox One Controller=device_section,WINEBUS\VID_045E&PID_02D1&MI_00 +Xbox One Controller (Covert Forces/Firmware 2015)=device_section,WINEBUS\VID_045E&PID_02DD +Xbox One Controller (Covert Forces/Firmware 2015)=device_section,WINEBUS\VID_045E&PID_02DD&MI_00 +Xbox One X Controller=device_section,WINEBUS\VID_045E&PID_02E0 +Xbox One X Controller=device_section,WINEBUS\VID_045E&PID_02E0&MI_00 +Xbox One Elite Controller=device_section,WINEBUS\VID_045E&PID_02E3 +Xbox One Elite Controller=device_section,WINEBUS\VID_045E&PID_02E3&MI_00 +Wireless XBox Controller Dongle=device_section,WINEBUS\VID_045E&PID_02E6 +Wireless XBox Controller Dongle=device_section,WINEBUS\VID_045E&PID_02E6&MI_00 +Xbox One S Controller=device_section,WINEBUS\VID_045E&PID_02EA +Xbox One S Controller=device_section,WINEBUS\VID_045E&PID_02EA&MI_00 +Xbox One S Controller (Firmware 2017)=device_section,WINEBUS\VID_045E&PID_02FD +Xbox One S Controller (Firmware 2017)=device_section,WINEBUS\VID_045E&PID_02FD&MI_00 +Xbox 360 Wireless Adapter=device_section,WINEBUS\VID_045E&PID_0719 +Xbox 360 Wireless Adapter=device_section,WINEBUS\VID_045E&PID_0719&MI_00
[device_section.Services] AddService = xinput,0x2,svc_section
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/main.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 42614b09f3a..65385055729 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -289,13 +289,26 @@ static WCHAR *get_device_id(DEVICE_OBJECT *device)
static WCHAR *get_hardware_ids(DEVICE_OBJECT *device) { + static const WCHAR input_formatW[] = {'&','M','I','_','%','0','2','u',0}; + static const WCHAR winebus_formatW[] = + { + 'W','I','N','E','B','U','S','\','V','I','D','_','%','0','4','X', + '&','P','I','D','_','%','0','4','X',0 + }; struct device_extension *ext = (struct device_extension *)device->DeviceExtension; + DWORD pos = 0, len = 0, input_len = 0, winebus_len = 25; WCHAR *dst;
- if ((dst = ExAllocatePool(PagedPool, (strlenW(ext->desc.busid) + 2) * sizeof(WCHAR)))) + if (ext->desc.input != -1) input_len = 14; + + len += winebus_len + input_len + 1; + + if ((dst = ExAllocatePool(PagedPool, (len + 1) * sizeof(WCHAR)))) { - strcpyW(dst, ext->desc.busid); - dst[strlenW(dst) + 1] = 0; + pos += snprintfW(dst + pos, len - pos, winebus_formatW, ext->desc.vid, ext->desc.pid); + if (input_len) pos += snprintfW(dst + pos, len - pos, input_formatW, ext->desc.input); + pos += 1; + dst[pos] = 0; }
return dst;
Native XBox controllers should now be listed in winexinput.inf, and the axis or button checks should be enough to set the compatible id anyway.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus.h | 2 -- dlls/winebus.sys/bus_iohid.c | 59 +++++++++++++++++------------------- dlls/winebus.sys/bus_udev.c | 13 ++------ dlls/winebus.sys/main.c | 13 -------- 4 files changed, 30 insertions(+), 57 deletions(-)
diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h index 75ff218c26d..c9af7cea1f0 100644 --- a/dlls/winebus.sys/bus.h +++ b/dlls/winebus.sys/bus.h @@ -34,6 +34,4 @@ DEVICE_OBJECT *bus_find_hid_device(const WCHAR *bus_id, void *platform_dev) DECL void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length) DECLSPEC_HIDDEN;
/* General Bus Functions */ -BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - extern HANDLE driver_key DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 3df60a1b516..25accb0d86e 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -316,46 +316,41 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * if (IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad) || IOHIDDeviceConformsTo(IOHIDDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick)) { - if (is_xbox_gamepad(desc.vid, desc.pid)) - desc.is_gamepad = TRUE; - else - { - int axes=0, buttons=0; - CFArrayRef element_array = IOHIDDeviceCopyMatchingElements( - IOHIDDevice, NULL, kIOHIDOptionsTypeNone); - - if (element_array) { - CFIndex index; - CFIndex count = CFArrayGetCount(element_array); - for (index = 0; index < count; index++) + int axes=0, buttons=0; + CFArrayRef element_array = IOHIDDeviceCopyMatchingElements( + IOHIDDevice, NULL, kIOHIDOptionsTypeNone); + + if (element_array) { + CFIndex index; + CFIndex count = CFArrayGetCount(element_array); + for (index = 0; index < count; index++) + { + IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(element_array, index); + if (element) { - IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(element_array, index); - if (element) + int type = IOHIDElementGetType(element); + if (type == kIOHIDElementTypeInput_Button) buttons++; + if (type == kIOHIDElementTypeInput_Axis) axes++; + if (type == kIOHIDElementTypeInput_Misc) { - int type = IOHIDElementGetType(element); - if (type == kIOHIDElementTypeInput_Button) buttons++; - if (type == kIOHIDElementTypeInput_Axis) axes++; - if (type == kIOHIDElementTypeInput_Misc) + uint32_t usage = IOHIDElementGetUsage(element); + switch (usage) { - uint32_t usage = IOHIDElementGetUsage(element); - switch (usage) - { - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - case kHIDUsage_GD_Slider: - axes ++; - } + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + axes ++; } } } - CFRelease(element_array); } - desc.is_gamepad = (axes == 6 && buttons >= 14); + CFRelease(element_array); } + desc.is_gamepad = (axes == 6 && buttons >= 14); }
TRACE("dev %p, desc %s.\n", IOHIDDevice, debugstr_device_desc(&desc)); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 78e74de842a..d650dd2ba3e 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1138,6 +1138,7 @@ static void udev_add_device(struct udev_device *dev) else if (!strcmp(subsystem, "input")) { struct input_id device_id = {0}; + int axes = 0, buttons = 0; char device_uid[255];
desc.busid = lnxev_busidW; @@ -1154,23 +1155,15 @@ static void udev_add_device(struct udev_device *dev) device_uid[0] = 0; if (ioctl(fd, EVIOCGUNIQ(254), device_uid) >= 0 && device_uid[0]) MultiByteToWideChar(CP_UNIXCP, 0, device_uid, -1, desc.serial, ARRAY_SIZE(desc.serial)); - } -#endif
- if (!desc.serial[0]) lstrcpyW(desc.serial, base_serial); - - if (is_xbox_gamepad(desc.vid, desc.pid)) - desc.is_gamepad = TRUE; -#ifdef HAS_PROPER_INPUT_HEADER - else - { - int axes=0, buttons=0; axes = count_abs_axis(fd); buttons = count_buttons(fd, NULL); desc.is_gamepad = (axes == 6 && buttons >= 14); } #endif
+ if (!desc.serial[0]) lstrcpyW(desc.serial, base_serial); + TRACE("dev %p, node %s, desc %s.\n", dev, debugstr_a(devnode), debugstr_device_desc(&desc));
if (strcmp(subsystem, "hidraw") == 0) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 65385055729..c505ff3a1f0 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -1094,19 +1094,6 @@ void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length) LeaveCriticalSection(&ext->cs); }
-BOOL is_xbox_gamepad(WORD vid, WORD pid) -{ - int i; - - if (vid != VID_MICROSOFT) - return FALSE; - - for (i = 0; i < ARRAY_SIZE(XBOX_CONTROLLERS); i++) - if (pid == XBOX_CONTROLLERS[i].pid) return TRUE; - - return FALSE; -} - static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo) { NTSTATUS ret;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winexinput.sys/main.c | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index 724552cfcac..e349286066c 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -32,6 +32,7 @@ #include "ddk/wdm.h" #include "ddk/hidport.h" #include "ddk/hidpddi.h" +#include "ddk/hidtypes.h"
#include "wine/asm.h" #include "wine/debug.h" @@ -314,17 +315,76 @@ static NTSTATUS try_complete_pending_read(DEVICE_OBJECT *device, IRP *irp) return IoCallDriver(fdo->bus_device, xinput_irp); }
+struct device_strings +{ + const WCHAR *id; + const WCHAR *product; +}; + +static const struct device_strings device_strings[] = +{ + { .id = L"VID_045E&PID_028E&IG_00", .product = L"Controller (XBOX 360 For Windows)" }, + { .id = L"VID_045E&PID_028F&IG_00", .product = L"Controller (XBOX 360 For Windows)" }, + { .id = L"VID_045E&PID_02D1&IG_00", .product = L"Controller (XBOX One For Windows)" }, + { .id = L"VID_045E&PID_02DD&IG_00", .product = L"Controller (XBOX One For Windows)" }, + { .id = L"VID_045E&PID_02E3&IG_00", .product = L"Controller (XBOX One For Windows)" }, + { .id = L"VID_045E&PID_02EA&IG_00", .product = L"Controller (XBOX One For Windows)" }, + { .id = L"VID_045E&PID_02FD&IG_00", .product = L"Controller (XBOX One For Windows)" }, + { .id = L"VID_045E&PID_0719&IG_00", .product = L"Controller (XBOX 360 For Windows)" }, +}; + +static const WCHAR *find_product_string(const WCHAR *device_id) +{ + const WCHAR *match_id = wcsrchr(device_id, '\') + 1; + DWORD i; + + for (i = 0; i < ARRAY_SIZE(device_strings); ++i) + if (!wcsicmp(device_strings[i].id, match_id)) + return device_strings[i].product; + + return NULL; +} + static NTSTATUS WINAPI gamepad_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); ULONG output_len = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; struct func_device *fdo = fdo_from_DEVICE_OBJECT(device); + struct device *impl = impl_from_DEVICE_OBJECT(device); + const WCHAR *str = NULL;
TRACE("device %p, irp %p, code %#x, bus_device %p.\n", device, irp, code, fdo->bus_device);
switch (code) { + case IOCTL_HID_GET_STRING: + switch ((ULONG_PTR)stack->Parameters.DeviceIoControl.Type3InputBuffer) + { + case HID_STRING_ID_IPRODUCT: + str = find_product_string(impl->device_id); + break; + } + + if (!str) + { + IoSkipCurrentIrpStackLocation(irp); + return IoCallDriver(fdo->bus_device, irp); + } + + irp->IoStatus.Information = (wcslen(str) + 1) * sizeof(WCHAR); + if (output_len < irp->IoStatus.Information) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + wcscpy(irp->UserBuffer, str); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + case IOCTL_HID_GET_DEVICE_DESCRIPTOR: { HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR *)irp->UserBuffer;
This should now be handled by xusb22.sys.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/main.c | 79 +---------------------------------------- 1 file changed, 1 insertion(+), 78 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index c505ff3a1f0..9404e73246b 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -66,32 +66,6 @@ struct product_desc const WCHAR* serialnumber; };
-#define VID_MICROSOFT 0x045e - -static const WCHAR xbox360_product_string[] = { - 'C','o','n','t','r','o','l','l','e','r',' ','(','X','B','O','X',' ','3','6','0',' ','F','o','r',' ','W','i','n','d','o','w','s',')',0 -}; - -static const WCHAR xboxone_product_string[] = { - 'C','o','n','t','r','o','l','l','e','r',' ','(','X','B','O','X',' ','O','n','e',' ','F','o','r',' ','W','i','n','d','o','w','s',')',0 -}; - -static const struct product_desc XBOX_CONTROLLERS[] = { - {VID_MICROSOFT, 0x0202, NULL, NULL, NULL}, /* Xbox Controller */ - {VID_MICROSOFT, 0x0285, NULL, NULL, NULL}, /* Xbox Controller S */ - {VID_MICROSOFT, 0x0289, NULL, NULL, NULL}, /* Xbox Controller S */ - {VID_MICROSOFT, 0x028e, NULL, xbox360_product_string, NULL}, /* Xbox360 Controller */ - {VID_MICROSOFT, 0x028f, NULL, xbox360_product_string, NULL}, /* Xbox360 Wireless Controller */ - {VID_MICROSOFT, 0x02d1, NULL, xboxone_product_string, NULL}, /* Xbox One Controller */ - {VID_MICROSOFT, 0x02dd, NULL, xboxone_product_string, NULL}, /* Xbox One Controller (Covert Forces/Firmware 2015) */ - {VID_MICROSOFT, 0x02e0, NULL, NULL, NULL}, /* Xbox One X Controller */ - {VID_MICROSOFT, 0x02e3, NULL, xboxone_product_string, NULL}, /* Xbox One Elite Controller */ - {VID_MICROSOFT, 0x02e6, NULL, NULL, NULL}, /* Wireless XBox Controller Dongle */ - {VID_MICROSOFT, 0x02ea, NULL, xboxone_product_string, NULL}, /* Xbox One S Controller */ - {VID_MICROSOFT, 0x02fd, NULL, xboxone_product_string, NULL}, /* Xbox One S Controller (Firmware 2017) */ - {VID_MICROSOFT, 0x0719, NULL, xbox360_product_string, NULL}, /* Xbox 360 Wireless Adapter */ -}; - static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *mouse_obj; @@ -838,55 +812,6 @@ static NTSTATUS deliver_last_report(struct device_extension *ext, DWORD buffer_l } }
-static NTSTATUS hid_get_native_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD length) -{ - struct device_extension *ext = (struct device_extension *)device->DeviceExtension; - const struct product_desc *vendor_products; - unsigned int i, vendor_products_size = 0; - - if (ext->desc.vid == VID_MICROSOFT) - { - vendor_products = XBOX_CONTROLLERS; - vendor_products_size = ARRAY_SIZE(XBOX_CONTROLLERS); - } - - for (i = 0; i < vendor_products_size; i++) - { - if (ext->desc.pid == vendor_products[i].pid) - break; - } - - if (i >= vendor_products_size) - return STATUS_UNSUCCESSFUL; - - switch (index) - { - case HID_STRING_ID_IPRODUCT: - if (vendor_products[i].product) - { - strcpyW(buffer, vendor_products[i].product); - return STATUS_SUCCESS; - } - break; - case HID_STRING_ID_IMANUFACTURER: - if (vendor_products[i].manufacturer) - { - strcpyW(buffer, vendor_products[i].manufacturer); - return STATUS_SUCCESS; - } - break; - case HID_STRING_ID_ISERIALNUMBER: - if (vendor_products[i].serialnumber) - { - strcpyW(buffer, vendor_products[i].serialnumber); - return STATUS_SUCCESS; - } - break; - } - - return STATUS_UNSUCCESSFUL; -} - static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); @@ -978,9 +903,7 @@ static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp) DWORD index = (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer; TRACE("IOCTL_HID_GET_STRING[%08x]\n", index);
- irp->IoStatus.Status = hid_get_native_string(device, index, (WCHAR *)irp->UserBuffer, buffer_len / sizeof(WCHAR)); - if (irp->IoStatus.Status != STATUS_SUCCESS) - irp->IoStatus.Status = unix_device_get_string(device, index, (WCHAR *)irp->UserBuffer, buffer_len / sizeof(WCHAR)); + irp->IoStatus.Status = unix_device_get_string(device, index, (WCHAR *)irp->UserBuffer, buffer_len / sizeof(WCHAR)); if (irp->IoStatus.Status == STATUS_SUCCESS) irp->IoStatus.Information = (strlenW((WCHAR *)irp->UserBuffer) + 1) * sizeof(WCHAR); break;