v4: After review from Andrew Eikum
Signed-off-by: Aric Stewart aric@codeweavers.com --- dlls/winebus.sys/bus_udev.c | 235 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 6 deletions(-)
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Fri, Jan 19, 2018 at 07:43:00AM -0600, Aric Stewart wrote:
v4: After review from Andrew Eikum
Signed-off-by: Aric Stewart aric@codeweavers.com
dlls/winebus.sys/bus_udev.c | 235 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 6 deletions(-)
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index b700da1fbb..f724884228 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -251,9 +251,16 @@ struct wine_input_absinfo { BYTE report_index; };
+enum {FIRST=0, NORMAL, DROPPED};
struct wine_input_private { struct platform_private base;
- int buffer_length;
- BYTE *last_report_buffer;
- BYTE *current_report_buffer;
- BYTE report_state;
- int report_descriptor_size; BYTE *report_descriptor;
@@ -359,7 +366,82 @@ static const BYTE* what_am_I(struct udev_device *dev) return Unknown; }
-static VOID build_report_descriptor(struct wine_input_private *ext, struct udev_device *dev) +static void set_button_value(struct wine_input_private *ext, int code, int value) +{
- int index = ext->button_map[code];
- int bindex = index / 8;
- int b = index % 8;
- BYTE mask;
- mask = 1<<b;
- if (value)
ext->current_report_buffer[bindex] = ext->current_report_buffer[bindex] | mask;- else
- {
mask = ~mask;ext->current_report_buffer[bindex] = ext->current_report_buffer[bindex] & mask;- }
+}
+static void set_abs_axis_value(struct wine_input_private *ext, int code, int value) +{
- int index;
- /* check for hatswitches */
- if (code <= ABS_HAT3Y && code >= ABS_HAT0X)
- {
index = code - ABS_HAT0X;ext->hat_values[index] = value;if ((code - ABS_HAT0X) % 2)index--;if (ext->hat_values[index] == 0){if (ext->hat_values[index+1] == 0)value = 8;else if (ext->hat_values[index+1] < 0)value = 0;elsevalue = 4;}else if (ext->hat_values[index] > 0){if (ext->hat_values[index+1] == 0)value = 2;else if (ext->hat_values[index+1] < 0)value = 1;elsevalue = 3;}else{if (ext->hat_values[index+1] == 0)value = 6;else if (ext->hat_values[index+1] < 0)value = 7;elsevalue = 5;}ext->current_report_buffer[ext->hat_map[index]] = value;- }
- else if (code < HID_ABS_MAX && ABS_TO_HID_MAP[code][0] != 0)
- {
index = ext->abs_map[code].report_index;*((DWORD*)&ext->current_report_buffer[index]) = LE_DWORD(value);- }
+}
+static void set_rel_axis_value(struct wine_input_private *ext, int code, int value) +{
- int index;
- if (code < HID_REL_MAX && REL_TO_HID_MAP[code][0] != 0)
- {
index = ext->rel_map[code];if (value > 127) value = 127;if (value < -127) value = -127;ext->current_report_buffer[index] = value;- }
+}
+static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_device *dev) { int abs_pages[TOP_ABS_PAGE][HID_ABS_MAX+1]; int rel_pages[TOP_REL_PAGE][HID_REL_MAX+1]; @@ -375,17 +457,17 @@ static VOID build_report_descriptor(struct wine_input_private *ext, struct udev_ if (ioctl(ext->base.device_fd, EVIOCGBIT(EV_REL, sizeof(relbits)), relbits) == -1) { WARN("ioctl(EVIOCGBIT, EV_REL) failed: %d %s\n", errno, strerror(errno));
return;
} if (ioctl(ext->base.device_fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) == -1) { WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));return FALSE;
return;
} if (ioctl(ext->base.device_fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits) == -1) { WARN("ioctl(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno));return FALSE;
return;
return FALSE;}
descript_size = sizeof(REPORT_HEADER) + sizeof(REPORT_TAIL);
@@ -480,6 +562,11 @@ static VOID build_report_descriptor(struct wine_input_private *ext, struct udev_ TRACE("Report will be %i bytes\n", report_size);
ext->report_descriptor = HeapAlloc(GetProcessHeap(), 0, descript_size);
if (!ext->report_descriptor)
{
ERR("Failed to alloc report descriptor\n");return FALSE;} report_ptr = ext->report_descriptor;
memcpy(report_ptr, REPORT_HEADER, sizeof(REPORT_HEADER));
@@ -529,6 +616,76 @@ static VOID build_report_descriptor(struct wine_input_private *ext, struct udev_ memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
ext->report_descriptor_size = descript_size;
- ext->buffer_length = report_size;
- ext->current_report_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, report_size);
- if (ext->current_report_buffer == NULL)
- {
ERR("Failed to alloc report buffer\n");HeapFree(GetProcessHeap(), 0, ext->report_descriptor);return FALSE;- }
- ext->last_report_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, report_size);
- if (ext->last_report_buffer == NULL)
- {
ERR("Failed to alloc report buffer\n");HeapFree(GetProcessHeap(), 0, ext->report_descriptor);HeapFree(GetProcessHeap(), 0, ext->current_report_buffer);return FALSE;- }
- ext->report_state = FIRST;
- /* Initialize axis in the report */
- for (i = 0; i < HID_ABS_MAX; i++)
if (test_bit(absbits, i))set_abs_axis_value(ext, i, ext->abs_map[i].info.value);- return TRUE;
+}
+static BOOL set_report_from_event(struct wine_input_private *ext, struct input_event *ie) +{
- switch(ie->type)
- {
+#ifdef EV_SYN
case EV_SYN:switch (ie->code){case SYN_REPORT:if (ext->report_state == NORMAL){memcpy(ext->last_report_buffer, ext->current_report_buffer, ext->buffer_length);return TRUE;}else{if (ext->report_state == DROPPED)memcpy(ext->current_report_buffer, ext->last_report_buffer, ext->buffer_length);ext->report_state = NORMAL;}break;case SYN_DROPPED:TRACE_(hid_report)("received SY_DROPPED\n");ext->report_state = DROPPED;}return FALSE;+#endif +#ifdef EV_MSC
case EV_MSC:return FALSE;+#endif
case EV_KEY:set_button_value(ext, ie->code, ie->value);return FALSE;case EV_ABS:set_abs_axis_value(ext, ie->code, ie->value);return FALSE;case EV_REL:set_rel_axis_value(ext, ie->code, ie->value);return FALSE;default:ERR("TODO: Process Report (%i, %i)\n",ie->type, ie->code);return FALSE;- }
} #endif
@@ -888,9 +1045,60 @@ static NTSTATUS lnxev_get_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buff return STATUS_SUCCESS; }
+static DWORD CALLBACK lnxev_device_report_thread(void *args) +{
- DEVICE_OBJECT *device = (DEVICE_OBJECT*)args;
- struct wine_input_private *private = input_impl_from_DEVICE_OBJECT(device);
- struct pollfd plfds[2];
- plfds[0].fd = private->base.device_fd;
- plfds[0].events = POLLIN;
- plfds[0].revents = 0;
- plfds[1].fd = private->base.control_pipe[0];
- plfds[1].events = POLLIN;
- plfds[1].revents = 0;
- while (1)
- {
int size;struct input_event ie;if (poll(plfds, 2, -1) <= 0) continue;if (plfds[1].revents || !private->current_report_buffer || private->buffer_length == 0)break;size = read(plfds[0].fd, &ie, sizeof(ie));if (size == -1)TRACE_(hid_report)("Read failed. Likely an unplugged device\n");else if (size == 0)TRACE_(hid_report)("Failed to read report\n");else if (set_report_from_event(private, &ie))process_hid_report(device, private->current_report_buffer, private->buffer_length);- }
- return 0;
+}
static NTSTATUS lnxev_begin_report_processing(DEVICE_OBJECT *device) {
- return STATUS_NOT_IMPLEMENTED;
- struct wine_input_private *private = input_impl_from_DEVICE_OBJECT(device);
- if (private->base.report_thread)
return STATUS_SUCCESS;- if (pipe(private->base.control_pipe) != 0)
- {
ERR("Control pipe creation failed\n");return STATUS_UNSUCCESSFUL;- }
- private->base.report_thread = CreateThread(NULL, 0, lnxev_device_report_thread, device, 0, NULL);
- if (!private->base.report_thread)
- {
ERR("Unable to create device report thread\n");close(private->base.control_pipe[0]);close(private->base.control_pipe[1]);return STATUS_UNSUCCESSFUL;- }
- return STATUS_SUCCESS;
}
static NTSTATUS lnxev_set_output_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *written) @@ -1017,7 +1225,15 @@ static void try_add_device(struct udev_device *dev) private->device_fd = fd; #ifdef HAS_PROPER_INPUT_HEADER if (strcmp(subsystem, "input") == 0)
build_report_descriptor((struct wine_input_private*)private, dev);
if (!build_report_descriptor((struct wine_input_private*)private, dev)){ERR("Building report descriptor failed, removing device\n");close(fd);udev_device_unref(dev);bus_remove_hid_device(device);HeapFree(GetProcessHeap(), 0, serial);return;}#endif IoInvalidateDeviceRelations(device, BusRelations); } @@ -1059,6 +1275,13 @@ static void try_remove_device(struct udev_device *dev) close(private->control_pipe[0]); close(private->control_pipe[1]); CloseHandle(private->report_thread); +#ifdef HAS_PROPER_INPUT_HEADER
if (strcmp(udev_device_get_subsystem(dev), "input") == 0){HeapFree(GetProcessHeap(), 0, ((struct wine_input_private*)private)->current_report_buffer);HeapFree(GetProcessHeap(), 0, ((struct wine_input_private*)private)->last_report_buffer);}+#endif }
#ifdef HAS_PROPER_INPUT_HEADER