[PATCH v5 4/5] winebus.sys: Process device reports for linux event devices

Andrew Eikum aeikum at codeweavers.com
Mon Jan 22 09:36:09 CST 2018


Signed-off-by: Andrew Eikum <aeikum at 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 at 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;
> +            else
> +                value = 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;
> +            else
> +                value = 3;
> +        }
> +        else
> +        {
> +            if (ext->hat_values[index+1] == 0)
> +                value = 6;
> +            else if (ext->hat_values[index+1] < 0)
> +                value = 7;
> +            else
> +                value = 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;
> +        return FALSE;
>      }
>      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;
> +        return FALSE;
>      }
>      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;
> +        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
> 

> 




More information about the wine-devel mailing list