[PATCH v2 8/9] evdev: add hotplug support

Kristian Høgsberg krh at bitplanet.net
Fri Oct 28 10:16:22 PDT 2011


On Wed, Oct 26, 2011 at 8:55 AM, Tiago Vignatti
<tiago.vignatti at intel.com> wrote:
> Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
> ---
> changes since v1:
> - moved seat number filter inside device_added, so it catches hotplugged
>  devices as well.

Looks good, I cherry picked this one too.

>  compositor/evdev.c |  128 +++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 116 insertions(+), 12 deletions(-)
>
> diff --git a/compositor/evdev.c b/compositor/evdev.c
> index 15052eb..aaaf0e5 100644
> --- a/compositor/evdev.c
> +++ b/compositor/evdev.c
> @@ -34,6 +34,9 @@
>
>  struct evdev_input {
>        struct wlsc_input_device base;
> +       struct wl_list devices_list;
> +       struct udev_monitor *udev_monitor;
> +       char *seat_id;
>  };
>
>  /* Event queue used to defer keyboard/button events until EV_SYN time. */
> @@ -49,6 +52,7 @@ struct evdev_event_queue {
>
>  struct evdev_input_device {
>        struct evdev_input *master;
> +       struct wl_list link;
>        struct wl_event_source *source;
>        struct wlsc_output *output;
>        int fd;
> @@ -62,6 +66,7 @@ struct evdev_input_device {
>
>        int is_touchpad, old_x_value, old_y_value, reset_x_value, reset_y_value;
>        uint32_t time;
> +       char *devnode;
>
>        /* Event queue used to defer keyboard/button events until EV_SYN time */
>        int num_queue;
> @@ -382,8 +387,11 @@ evdev_input_device_data(int fd, uint32_t mask, void *data)
>        {
>                len = read(fd, &ev, sizeof(ev));
>                if (len <= 0) {
> -                       /* FIXME: handle error... reopen device? */
> -                       fprintf(stderr, "input read error %s", strerror(errno));
> +                       if (errno == ENODEV)
> +                               close(device->fd);
> +                       else
> +                               fprintf(stderr, "input read error %s\n",
> +                                       strerror(errno));
>                        break;
>                }
>                /* The kernel promises that we always only read a complete
> @@ -472,6 +480,7 @@ evdev_input_device_create(struct evdev_input *master,
>        device->dx = 0;
>        device->dy = 0;
>        device->num_queue = 0;
> +       device->devnode = strdup(path);
>
>        ec = (struct wlsc_compositor *) master->base.input_device.compositor;
>        device->output =
> @@ -482,6 +491,7 @@ evdev_input_device_create(struct evdev_input *master,
>
>        device->fd = open(path, O_RDONLY);
>        if (device->fd < 0) {
> +               free(device->devnode);
>                free(device);
>                fprintf(stderr, "couldn't create pointer for %s: %m\n", path);
>                return NULL;
> @@ -489,6 +499,7 @@ evdev_input_device_create(struct evdev_input *master,
>
>        if (evdev_configure_device(device) == -1) {
>                close(device->fd);
> +               free(device->devnode);
>                free(device);
>                return NULL;
>        }
> @@ -499,15 +510,109 @@ evdev_input_device_create(struct evdev_input *master,
>                                              evdev_input_device_data, device);
>        if (device->source == NULL) {
>                close(device->fd);
> +               free(device->devnode);
>                free(device);
>                return NULL;
>        }
>
> +       wl_list_insert(master->devices_list.prev, &device->link);
>        return device;
>  }
>
>  static const char default_seat[] = "seat0";
>
> +static void
> +device_added(struct udev_device *udev_device, struct evdev_input *master)
> +{
> +       struct wlsc_compositor *c;
> +       const char *devnode;
> +       const char *device_seat;
> +
> +       device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
> +       if (!device_seat)
> +               device_seat = default_seat;
> +
> +       if (strcmp(device_seat, master->seat_id))
> +               return;
> +
> +       c = (struct wlsc_compositor *) master->base.input_device.compositor;
> +       devnode = udev_device_get_devnode(udev_device);
> +       if (evdev_input_device_create(master, c->wl_display, devnode))
> +               fprintf(stderr, "evdev input device: added: %s\n", devnode);
> +}
> +
> +static void
> +device_removed(struct udev_device *udev_device, struct evdev_input *master)
> +{
> +       const char *devnode = udev_device_get_devnode(udev_device);
> +       struct evdev_input_device *device, *next;
> +
> +       wl_list_for_each_safe(device, next, &master->devices_list, link) {
> +               if (!strcmp(device->devnode, devnode)) {
> +                       wl_event_source_remove(device->source);
> +                       wl_list_remove(&device->link);
> +                       close(device->fd);
> +                       free(device->devnode);
> +                       free(device);
> +                       break;
> +               }
> +       }
> +       fprintf(stderr, "evdev input device: removed: %s\n", devnode);
> +}
> +
> +static int
> +evdev_udev_handler(int fd, uint32_t mask, void *data)
> +{
> +       struct evdev_input *master = data;
> +       struct udev_device *udev_device;
> +       const char *action;
> +
> +       udev_device = udev_monitor_receive_device(master->udev_monitor);
> +       if (!udev_device)
> +               return 1;
> +
> +       action = udev_device_get_action(udev_device);
> +       if (action) {
> +               if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
> +                       return 0;
> +
> +               if (!strcmp(action, "add")) {
> +                       device_added(udev_device, master);
> +               }
> +               else if (!strcmp(action, "remove"))
> +                       device_removed(udev_device, master);
> +       }
> +       udev_device_unref(udev_device);
> +
> +       return 0;
> +}
> +
> +static int
> +evdev_config_udev_monitor(struct udev *udev, struct evdev_input *master)
> +{
> +       struct wl_event_loop *loop;
> +       struct wlsc_compositor *c =
> +           (struct wlsc_compositor *) master->base.input_device.compositor;
> +
> +       master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
> +       if (!master->udev_monitor)
> +               return 0;
> +
> +       udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
> +                       "input", NULL);
> +
> +       if (udev_monitor_enable_receiving(master->udev_monitor)) {
> +               fprintf(stderr, "udev: failed to bind the udev monitor\n");
> +               return 0;
> +       }
> +
> +       loop = wl_display_get_event_loop(c->wl_display);
> +       wl_event_loop_add_fd(loop, udev_monitor_get_fd(master->udev_monitor),
> +                            WL_EVENT_READABLE, evdev_udev_handler, master);
> +
> +       return 1;
> +}
> +
>  void
>  evdev_input_add_devices(struct wlsc_compositor *c,
>                        struct udev *udev, const char *seat)
> @@ -516,7 +621,6 @@ evdev_input_add_devices(struct wlsc_compositor *c,
>        struct udev_enumerate *e;
>        struct udev_list_entry *entry;
>        struct udev_device *device;
> -       const char *device_seat;
>        const char *path;
>
>        input = malloc(sizeof *input);
> @@ -526,6 +630,14 @@ evdev_input_add_devices(struct wlsc_compositor *c,
>        memset(input, 0, sizeof *input);
>        wlsc_input_device_init(&input->base, c);
>
> +       wl_list_init(&input->devices_list);
> +       input->seat_id = strdup(seat);
> +       if (!evdev_config_udev_monitor(udev, input)) {
> +               free(input->seat_id);
> +               free(input);
> +               return;
> +       }
> +
>        e = udev_enumerate_new(udev);
>        udev_enumerate_add_match_subsystem(e, "input");
>        udev_enumerate_scan_devices(e);
> @@ -536,15 +648,7 @@ evdev_input_add_devices(struct wlsc_compositor *c,
>                if (strncmp("event", udev_device_get_sysname(device), 5) != 0)
>                        continue;
>
> -                device_seat =
> -                       udev_device_get_property_value(device, "ID_SEAT");
> -               if (!device_seat)
> -                       device_seat = default_seat;
> -
> -               if (strcmp(device_seat, seat) == 0) {
> -                       evdev_input_device_create(input, c->wl_display,
> -                                                 udev_device_get_devnode(device));
> -               }
> +               device_added(device, input);
>
>                udev_device_unref(device);
>        }
> --
> 1.7.5.4
>
>


More information about the wayland-devel mailing list