And use them for mouse and keyboard.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/Makefile.in | 1 + dlls/winebus.sys/controller.h | 20 ++++++++ dlls/winebus.sys/hid.c | 91 +++++++++++++++++++++++++++++++++++ dlls/winebus.sys/main.c | 41 ++++++++-------- 4 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 dlls/winebus.sys/hid.c
diff --git a/dlls/winebus.sys/Makefile.in b/dlls/winebus.sys/Makefile.in index 9011bbb6075..8cde3c7b422 100644 --- a/dlls/winebus.sys/Makefile.in +++ b/dlls/winebus.sys/Makefile.in @@ -8,6 +8,7 @@ C_SRCS = \ bus_iohid.c \ bus_sdl.c \ bus_udev.c \ + hid.c \ main.c
RC_SRCS = winebus.rc diff --git a/dlls/winebus.sys/controller.h b/dlls/winebus.sys/controller.h index 2f4a72a94cd..aa838129ce2 100644 --- a/dlls/winebus.sys/controller.h +++ b/dlls/winebus.sys/controller.h @@ -18,6 +18,26 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <stdarg.h> + +#include <windef.h> +#include <winbase.h> +#include <hidusage.h> + +struct hid_descriptor +{ + BYTE *data; + SIZE_T size; + SIZE_T max_size; +}; + +extern BOOL hid_descriptor_append(struct hid_descriptor *desc, const BYTE *buffer, SIZE_T size) DECLSPEC_HIDDEN; +extern BOOL hid_descriptor_begin(struct hid_descriptor *desc, USAGE usage_page, USAGE usage) DECLSPEC_HIDDEN; +extern BOOL hid_descriptor_end(struct hid_descriptor *desc) DECLSPEC_HIDDEN; + +extern BOOL hid_descriptor_add_buttons(struct hid_descriptor *desc, USAGE usage_page, + USAGE usage_min, USAGE usage_max) DECLSPEC_HIDDEN; + /* Blocks of data for building HID device descriptions */
#include "psh_hid_macros.h" diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c new file mode 100644 index 00000000000..052037ec19e --- /dev/null +++ b/dlls/winebus.sys/hid.c @@ -0,0 +1,91 @@ +/* + * Common HID report descriptor helpers + * + * 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 "controller.h" + +BOOL hid_descriptor_append(struct hid_descriptor *desc, const BYTE *buffer, SIZE_T size) +{ + BYTE *tmp = desc->data; + + if (desc->size + size > desc->max_size) + { + desc->max_size = max(desc->max_size * 3 / 2, desc->size + size); + if (!desc->data) desc->data = HeapAlloc(GetProcessHeap(), 0, desc->max_size); + else desc->data = HeapReAlloc(GetProcessHeap(), 0, tmp, desc->max_size); + } + + if (!desc->data) + { + HeapFree(GetProcessHeap(), 0, tmp); + return FALSE; + } + + memcpy(desc->data + desc->size, buffer, size); + desc->size += size; + return TRUE; +} + +#include "psh_hid_macros.h" + +BOOL hid_descriptor_begin(struct hid_descriptor *desc, USAGE usage_page, USAGE usage) +{ + const BYTE template[] = + { + USAGE_PAGE(2, usage_page), + USAGE(2, usage), + COLLECTION(1, Application), + USAGE(1, 0), + }; + + memset(desc, 0, sizeof(*desc)); + return hid_descriptor_append(desc, template, sizeof(template)); +} + +BOOL hid_descriptor_end(struct hid_descriptor *desc) +{ + static const BYTE template[] = + { + END_COLLECTION, + }; + + return hid_descriptor_append(desc, template, sizeof(template)); +} + +BOOL hid_descriptor_add_buttons(struct hid_descriptor *desc, USAGE usage_page, + USAGE usage_min, USAGE usage_max) +{ + const BYTE template[] = + { + USAGE_PAGE(2, usage_page), + USAGE_MINIMUM(2, usage_min), + USAGE_MAXIMUM(2, usage_max), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_COUNT(2, usage_max - usage_min + 1), + REPORT_SIZE(1, 1), + INPUT(1, Data|Var|Abs), + }; + + return hid_descriptor_append(desc, template, sizeof(template)); +} + +#include "pop_hid_macros.h" diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 6ceccd21442..84885bdcce9 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -94,7 +94,9 @@ static const struct product_desc XBOX_CONTROLLERS[] = { static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *mouse_obj; +static struct hid_descriptor mouse_desc; static DEVICE_OBJECT *keyboard_obj; +static struct hid_descriptor keyboard_desc;
/* The root-enumerated device stack. */ DEVICE_OBJECT *bus_pdo; @@ -483,16 +485,10 @@ static NTSTATUS mouse_get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffer, { TRACE("buffer %p, length %u.\n", buffer, length);
- *ret_length = sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS) + sizeof(REPORT_TAIL); - if (length < sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS) + sizeof(REPORT_TAIL)) - return STATUS_BUFFER_TOO_SMALL; - - memcpy(buffer, REPORT_HEADER, sizeof(REPORT_HEADER)); - add_button_block(buffer + sizeof(REPORT_HEADER), 1, 3); - memcpy(buffer + sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS), REPORT_TAIL, sizeof(REPORT_TAIL)); - buffer[IDX_HEADER_PAGE] = HID_USAGE_PAGE_GENERIC; - buffer[IDX_HEADER_USAGE] = HID_USAGE_GENERIC_MOUSE; + *ret_length = mouse_desc.size; + if (length < mouse_desc.size) return STATUS_BUFFER_TOO_SMALL;
+ memcpy(buffer, mouse_desc.data, mouse_desc.size); return STATUS_SUCCESS; }
@@ -545,6 +541,13 @@ static void mouse_device_create(void) { static const WCHAR busidW[] = {'W','I','N','E','M','O','U','S','E',0};
+ if (!hid_descriptor_begin(&mouse_desc, HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE)) + return; + if (!hid_descriptor_add_buttons(&mouse_desc, HID_USAGE_PAGE_BUTTON, 1, 3)) + return; + if (!hid_descriptor_end(&mouse_desc)) + return; + mouse_obj = bus_create_hid_device(busidW, 0, 0, -1, 0, 0, busidW, FALSE, &mouse_vtbl, 0); IoInvalidateDeviceRelations(bus_pdo, BusRelations); } @@ -557,17 +560,10 @@ static NTSTATUS keyboard_get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffe { TRACE("buffer %p, length %u.\n", buffer, length);
- *ret_length = sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS) + sizeof(REPORT_TAIL); - if (length < sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS) + sizeof(REPORT_TAIL)) - return STATUS_BUFFER_TOO_SMALL; - - memcpy(buffer, REPORT_HEADER, sizeof(REPORT_HEADER)); - add_button_block(buffer + sizeof(REPORT_HEADER), 0, 101); - buffer[sizeof(REPORT_HEADER) + IDX_BUTTON_USAGE_PAGE] = HID_USAGE_PAGE_KEYBOARD; - memcpy(buffer + sizeof(REPORT_HEADER) + sizeof(REPORT_BUTTONS), REPORT_TAIL, sizeof(REPORT_TAIL)); - buffer[IDX_HEADER_PAGE] = HID_USAGE_PAGE_GENERIC; - buffer[IDX_HEADER_USAGE] = HID_USAGE_GENERIC_KEYBOARD; + *ret_length = keyboard_desc.size; + if (length < keyboard_desc.size) return STATUS_BUFFER_TOO_SMALL;
+ memcpy(buffer, keyboard_desc.data, keyboard_desc.size); return STATUS_SUCCESS; }
@@ -620,6 +616,13 @@ static void keyboard_device_create(void) { static const WCHAR busidW[] = {'W','I','N','E','K','E','Y','B','O','A','R','D',0};
+ if (!hid_descriptor_begin(&keyboard_desc, HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_KEYBOARD)) + return; + if (!hid_descriptor_add_buttons(&keyboard_desc, HID_USAGE_PAGE_KEYBOARD, 0, 101)) + return; + if (!hid_descriptor_end(&keyboard_desc)) + return; + keyboard_obj = bus_create_hid_device(busidW, 0, 0, -1, 0, 0, busidW, FALSE, &keyboard_vtbl, 0); IoInvalidateDeviceRelations(bus_pdo, BusRelations); }