winebus.sys: Report lnxev axes individually in the descriptor.

Fixing invalid axis range when they differ between two axis of the same
usage page.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-08-13 09:46:14 +02:00 committed by Alexandre Julliard
parent dba263756c
commit f884ee46fb
1 changed files with 50 additions and 94 deletions

View File

@ -62,6 +62,7 @@
#include "winternl.h" #include "winternl.h"
#include "ddk/wdm.h" #include "ddk/wdm.h"
#include "ddk/hidtypes.h" #include "ddk/hidtypes.h"
#include "ddk/hidsdi.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/heap.h" #include "wine/heap.h"
#include "wine/unicode.h" #include "wine/unicode.h"
@ -345,10 +346,9 @@ static INT count_abs_axis(int device_fd)
static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_device *dev) static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_device *dev)
{ {
struct input_absinfo abs_info[HID_ABS_MAX]; struct input_absinfo abs_info[HID_ABS_MAX];
int abs_pages[TOP_ABS_PAGE][HID_ABS_MAX+1];
int rel_pages[TOP_REL_PAGE][HID_REL_MAX+1];
BYTE absbits[(ABS_MAX+7)/8]; BYTE absbits[(ABS_MAX+7)/8];
BYTE relbits[(REL_MAX+7)/8]; BYTE relbits[(REL_MAX+7)/8];
USAGE_AND_PAGE usage;
INT i; INT i;
INT report_size; INT report_size;
INT button_count, abs_count, rel_count, hat_count; INT button_count, abs_count, rel_count, hat_count;
@ -367,107 +367,47 @@ static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_
report_size = 0; report_size = 0;
abs_count = 0; if (!hid_descriptor_begin(&ext->desc, device_usage[0], device_usage[1]))
memset(abs_pages, 0, sizeof(abs_pages)); return FALSE;
for (i = 0; i < HID_ABS_MAX; i++)
if (test_bit(absbits, i))
{
abs_pages[ABS_TO_HID_MAP[i][0]][0]++;
abs_pages[ABS_TO_HID_MAP[i][0]][abs_pages[ABS_TO_HID_MAP[i][0]][0]] = i;
ioctl(ext->base.device_fd, EVIOCGABS(i), abs_info + i); abs_count = 0;
} for (i = 0; i < HID_ABS_MAX; i++)
/* Skip page 0, aka HID_USAGE_PAGE_UNDEFINED */ {
for (i = 1; i < TOP_ABS_PAGE; i++) if (!test_bit(absbits, i)) continue;
if (abs_pages[i][0] > 0) ioctl(ext->base.device_fd, EVIOCGABS(i), abs_info + i);
{
int j; if (!(usage.UsagePage = ABS_TO_HID_MAP[i][0])) continue;
for (j = 1; j <= abs_pages[i][0]; j++) if (!(usage.Usage = ABS_TO_HID_MAP[i][1])) continue;
{
ext->abs_map[abs_pages[i][j]] = report_size; if (!hid_descriptor_add_axes(&ext->desc, 1, usage.UsagePage, &usage.Usage, FALSE, 32,
report_size+=4; LE_DWORD(abs_info[i].minimum), LE_DWORD(abs_info[i].maximum)))
} return FALSE;
abs_count++;
} ext->abs_map[i] = report_size;
report_size += 4;
abs_count++;
}
rel_count = 0; rel_count = 0;
memset(rel_pages, 0, sizeof(rel_pages));
for (i = 0; i < HID_REL_MAX; i++) for (i = 0; i < HID_REL_MAX; i++)
if (test_bit(relbits, i)) {
{ if (!test_bit(relbits, i)) continue;
rel_pages[REL_TO_HID_MAP[i][0]][0]++; if (!(usage.UsagePage = REL_TO_HID_MAP[i][0])) continue;
rel_pages[REL_TO_HID_MAP[i][0]][rel_pages[REL_TO_HID_MAP[i][0]][0]] = i; if (!(usage.Usage = REL_TO_HID_MAP[i][1])) continue;
}
/* Skip page 0, aka HID_USAGE_PAGE_UNDEFINED */ if (!hid_descriptor_add_axes(&ext->desc, 1, usage.UsagePage, &usage.Usage, TRUE, 8,
for (i = 1; i < TOP_REL_PAGE; i++) 0x81, 0x7f))
if (rel_pages[i][0] > 0) return FALSE;
{
int j; ext->rel_map[i] = report_size;
for (j = 1; j <= rel_pages[i][0]; j++) report_size++;
{ rel_count++;
ext->rel_map[rel_pages[i][j]] = report_size; }
report_size++;
}
rel_count++;
}
/* For now lump all buttons just into incremental usages, Ignore Keys */ /* For now lump all buttons just into incremental usages, Ignore Keys */
ext->button_start = report_size; ext->button_start = report_size;
button_count = count_buttons(ext->base.device_fd, ext->button_map); button_count = count_buttons(ext->base.device_fd, ext->button_map);
if (button_count) if (button_count)
{
report_size += (button_count + 7) / 8;
}
hat_count = 0;
for (i = ABS_HAT0X; i <=ABS_HAT3X; i+=2)
if (test_bit(absbits, i))
{
ext->hat_map[i - ABS_HAT0X] = report_size;
ext->hat_values[i - ABS_HAT0X] = 0;
ext->hat_values[i - ABS_HAT0X + 1] = 0;
report_size++;
hat_count++;
}
TRACE("Report will be %i bytes\n", report_size);
if (!hid_descriptor_begin(&ext->desc, device_usage[0], device_usage[1]))
return FALSE;
if (abs_count)
{
for (i = 1; i < TOP_ABS_PAGE; i++)
{
if (abs_pages[i][0])
{
USAGE usages[HID_ABS_MAX];
int j;
for (j = 0; j < abs_pages[i][0]; j++)
usages[j] = ABS_TO_HID_MAP[abs_pages[i][j+1]][1];
if (!hid_descriptor_add_axes(&ext->desc, abs_pages[i][0], i, usages, FALSE, 32,
LE_DWORD(abs_info[abs_pages[i][1]].minimum),
LE_DWORD(abs_info[abs_pages[i][1]].maximum)))
return FALSE;
}
}
}
if (rel_count)
{
for (i = 1; i < TOP_REL_PAGE; i++)
{
if (rel_pages[i][0])
{
USAGE usages[HID_REL_MAX];
int j;
for (j = 0; j < rel_pages[i][0]; j++)
usages[j] = REL_TO_HID_MAP[rel_pages[i][j+1]][1];
if (!hid_descriptor_add_axes(&ext->desc, rel_pages[i][0], i, usages, TRUE, 8, 0x81, 0x7f))
return FALSE;
}
}
}
if (button_count)
{ {
if (!hid_descriptor_add_buttons(&ext->desc, HID_USAGE_PAGE_BUTTON, 1, button_count)) if (!hid_descriptor_add_buttons(&ext->desc, HID_USAGE_PAGE_BUTTON, 1, button_count))
return FALSE; return FALSE;
@ -478,7 +418,21 @@ static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_
if (!hid_descriptor_add_padding(&ext->desc, padding)) if (!hid_descriptor_add_padding(&ext->desc, padding))
return FALSE; return FALSE;
} }
report_size += (button_count + 7) / 8;
} }
hat_count = 0;
for (i = ABS_HAT0X; i <=ABS_HAT3X; i+=2)
{
if (!test_bit(absbits, i)) continue;
ext->hat_map[i - ABS_HAT0X] = report_size;
ext->hat_values[i - ABS_HAT0X] = 0;
ext->hat_values[i - ABS_HAT0X + 1] = 0;
report_size++;
hat_count++;
}
if (hat_count) if (hat_count)
{ {
if (!hid_descriptor_add_hatswitch(&ext->desc, hat_count)) if (!hid_descriptor_add_hatswitch(&ext->desc, hat_count))
@ -488,6 +442,8 @@ static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_
if (!hid_descriptor_end(&ext->desc)) if (!hid_descriptor_end(&ext->desc))
return FALSE; return FALSE;
TRACE("Report will be %i bytes\n", report_size);
ext->buffer_length = report_size; ext->buffer_length = report_size;
if (!(ext->current_report_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, report_size))) if (!(ext->current_report_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, report_size)))
goto failed; goto failed;