From de050c974ba5ae1b2ed944bd8f4ecf5712fcd8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Sep 2021 10:30:43 +0200 Subject: [PATCH] winebus.sys: Compute offsets while building the report descriptor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/winebus.sys/hid.c | 83 +++++++++++++++++++++++++++++++++ dlls/winebus.sys/unix_private.h | 14 ++++++ 2 files changed, 97 insertions(+) diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 98eb5341a2e..6d3dae5690d 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -32,8 +32,12 @@ #include "hidusage.h" #include "ddk/wdm.h" +#include "wine/debug.h" + #include "unix_private.h" +WINE_DEFAULT_DEBUG_CHANNEL(plugplay); + static BOOL hid_report_descriptor_append(struct hid_report_descriptor *desc, const BYTE *buffer, SIZE_T size) { BYTE *tmp = desc->data; @@ -93,6 +97,25 @@ BOOL hid_device_end_report_descriptor(struct unix_device *iface) return hid_report_descriptor_append(desc, template, sizeof(template)); } +static BOOL hid_device_add_button_count(struct unix_device *iface, BYTE count) +{ + USHORT offset = iface->hid_device_state.bit_size / 8; + + if ((iface->hid_device_state.bit_size % 8) && !iface->hid_device_state.button_count) + ERR("buttons should start byte aligned, missing padding!\n"); + else if (iface->hid_device_state.bit_size + count > 0x80000) + ERR("report size overflow, too many elements!\n"); + else + { + if (!iface->hid_device_state.button_count) iface->hid_device_state.button_start = offset; + iface->hid_device_state.button_count += count; + iface->hid_device_state.bit_size += count; + return TRUE; + } + + return FALSE; +} + BOOL hid_device_add_buttons(struct unix_device *iface, USAGE usage_page, USAGE usage_min, USAGE usage_max) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; @@ -117,6 +140,9 @@ BOOL hid_device_add_buttons(struct unix_device *iface, USAGE usage_page, USAGE u INPUT(1, Cnst|Var|Abs), }; + if (!hid_device_add_button_count(iface, usage_max - usage_min + 1)) + return FALSE; + if (!hid_report_descriptor_append(desc, template, sizeof(template))) return FALSE; @@ -126,6 +152,27 @@ BOOL hid_device_add_buttons(struct unix_device *iface, USAGE usage_page, USAGE u return TRUE; } +static BOOL hid_device_add_hatswitch_count(struct unix_device *iface, BYTE count) +{ + USHORT offset = iface->hid_device_state.bit_size / 8; + + if (iface->hid_device_state.button_count) + ERR("hatswitches should be added before buttons!\n"); + else if ((iface->hid_device_state.bit_size % 8)) + ERR("hatswitches should be byte aligned, missing padding!\n"); + else if (iface->hid_device_state.bit_size + 8 * count > 0x80000) + ERR("report size overflow, too many elements!\n"); + else + { + if (!iface->hid_device_state.hatswitch_count) iface->hid_device_state.hatswitch_start = offset; + iface->hid_device_state.hatswitch_count += count; + iface->hid_device_state.bit_size += 8 * count; + return TRUE; + } + + return FALSE; +} + BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count) { struct hid_report_descriptor *desc = &iface->hid_report_descriptor; @@ -143,9 +190,42 @@ BOOL hid_device_add_hatswitch(struct unix_device *iface, INT count) INPUT(1, Data|Var|Abs|Null), }; + if (!hid_device_add_hatswitch_count(iface, count)) + return FALSE; + return hid_report_descriptor_append(desc, template, sizeof(template)); } +static BOOL hid_device_add_axis_count(struct unix_device *iface, BOOL rel, BYTE count) +{ + USHORT offset = iface->hid_device_state.bit_size / 8; + + if (!rel && iface->hid_device_state.rel_axis_count) + ERR("absolute axes should be added before relative axes!\n"); + else if (iface->hid_device_state.button_count || iface->hid_device_state.hatswitch_count) + ERR("axes should be added before buttons or hatswitches!\n"); + else if ((iface->hid_device_state.bit_size % 8)) + ERR("axes should be byte aligned, missing padding!\n"); + else if (iface->hid_device_state.bit_size + 32 * count > 0x80000) + ERR("report size overflow, too many elements!\n"); + else if (rel) + { + if (!iface->hid_device_state.rel_axis_count) iface->hid_device_state.rel_axis_start = offset; + iface->hid_device_state.rel_axis_count += count; + iface->hid_device_state.bit_size += 32 * count; + return TRUE; + } + else + { + if (!iface->hid_device_state.abs_axis_count) iface->hid_device_state.abs_axis_start = offset; + iface->hid_device_state.abs_axis_count += count; + iface->hid_device_state.bit_size += 32 * count; + return TRUE; + } + + return FALSE; +} + BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page, const USAGE *usages, BOOL rel, LONG min, LONG max) { @@ -171,6 +251,9 @@ BOOL hid_device_add_axes(struct unix_device *iface, BYTE count, USAGE usage_page }; int i; + if (!hid_device_add_axis_count(iface, rel, count)) + return FALSE; + if (!hid_report_descriptor_append(desc, template_begin, sizeof(template_begin))) return FALSE; diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index d1d48737e67..acb2f45aca3 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -57,6 +57,19 @@ struct hid_report_descriptor SIZE_T max_size; }; +struct hid_device_state +{ + ULONG bit_size; + USHORT abs_axis_start; + USHORT abs_axis_count; + USHORT rel_axis_start; + USHORT rel_axis_count; + USHORT hatswitch_start; + USHORT hatswitch_count; + USHORT button_start; + USHORT button_count; +}; + struct unix_device { const struct raw_device_vtbl *vtbl; @@ -65,6 +78,7 @@ struct unix_device const struct hid_device_vtbl *hid_vtbl; struct hid_report_descriptor hid_report_descriptor; + struct hid_device_state hid_device_state; }; extern void *raw_device_create(const struct raw_device_vtbl *vtbl, SIZE_T size) DECLSPEC_HIDDEN;