touchpad: hook up pointer acceleration configuration
[platform/upstream/libinput.git] / src / path.c
index f2962bf..3752751 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <string.h>
 #include <libudev.h>
 #include "path.h"
 #include "evdev.h"
 
+static const char default_seat[] = "seat0";
+static const char default_seat_name[] = "default";
+
 int path_input_process_event(struct libinput_event);
 static void path_seat_destroy(struct libinput_seat *seat);
 
 static void
-path_input_disable(struct libinput *libinput)
+path_disable_device(struct libinput *libinput,
+                   struct evdev_device *device)
 {
-       struct path_input *input = (struct path_input*)libinput;
-       struct evdev_device *device = input->device;
-       struct path_seat *seat, *tmp;
+       struct libinput_seat *seat = device->base.seat;
+       struct evdev_device *dev, *next;
+
+       list_for_each_safe(dev, next,
+                          &seat->devices_list, base.link) {
+               if (dev != device)
+                       continue;
 
-       if (device) {
-               close_restricted(libinput, device->fd);
                evdev_device_remove(device);
-               input->device = NULL;
+               break;
        }
+}
 
-       /* should only be one seat anyway */
-       list_for_each_safe(seat, tmp, &libinput->seat_list, base.link) {
-               list_remove(&seat->base.link);
-               list_init(&seat->base.link);
+static void
+path_input_disable(struct libinput *libinput)
+{
+       struct path_input *input = (struct path_input*)libinput;
+       struct path_seat *seat, *tmp;
+       struct evdev_device *device, *next;
+
+       list_for_each_safe(seat, tmp, &input->base.seat_list, base.link) {
+               libinput_seat_ref(&seat->base);
+               list_for_each_safe(device, next,
+                                  &seat->base.devices_list, base.link)
+                       path_disable_device(libinput, device);
                libinput_seat_unref(&seat->base);
        }
 }
@@ -61,7 +77,9 @@ path_seat_destroy(struct libinput_seat *seat)
 }
 
 static struct path_seat*
-path_seat_create(struct path_input *input)
+path_seat_create(struct path_input *input,
+                const char *seat_name,
+                const char *seat_logical_name)
 {
        struct path_seat *seat;
 
@@ -69,22 +87,40 @@ path_seat_create(struct path_input *input)
        if (!seat)
                return NULL;
 
-       seat->name = "default";
-
-       /* FIXME: get physical seat from udev */
-       libinput_seat_init(&seat->base, &input->base, seat->name, seat->name, path_seat_destroy);
-       list_insert(&input->base.seat_list, &seat->base.link);
+       libinput_seat_init(&seat->base, &input->base, seat_name,
+                          seat_logical_name, path_seat_destroy);
 
        return seat;
 }
 
-static char *
-path_get_sysname(const char *path)
+static struct path_seat*
+path_seat_get_named(struct path_input *input,
+                   const char *seat_name_physical,
+                   const char *seat_name_logical)
+{
+       struct path_seat *seat;
+
+       list_for_each(seat, &input->base.seat_list, base.link) {
+               if (strcmp(seat->base.physical_name, seat_name_physical) == 0 &&
+                   strcmp(seat->base.logical_name, seat_name_logical) == 0)
+                       return seat;
+       }
+
+       return NULL;
+}
+
+static int
+path_get_udev_properties(const char *path,
+                        char **sysname,
+                        char **syspath,
+                        char **seat_name,
+                        char **seat_logical_name)
 {
        struct udev *udev = NULL;
        struct udev_device *device = NULL;
        struct stat st;
-       char *syspath = NULL;
+       const char *seat;
+       int rc = -1;
 
        udev = udev_new();
        if (!udev)
@@ -97,59 +133,92 @@ path_get_sysname(const char *path)
        if (!device)
                goto out;
 
-       syspath = strdup(udev_device_get_syspath(device));
+       *sysname = strdup(udev_device_get_sysname(device));
+       *syspath = strdup(udev_device_get_syspath(device));
+
+       seat = udev_device_get_property_value(device, "ID_SEAT");
+       *seat_name = strdup(seat ? seat : default_seat);
+
+       seat = udev_device_get_property_value(device, "WL_SEAT");
+       *seat_logical_name = strdup(seat ? seat : default_seat_name);
+
+       rc = 0;
+
 out:
        if (device)
                udev_device_unref(device);
        if (udev)
                udev_unref(udev);
-       return syspath;
+       return rc;
 }
 
-static int
-path_input_enable(struct libinput *libinput)
+static struct libinput_device *
+path_device_enable(struct path_input *input, const char *devnode)
 {
-       struct path_input *input = (struct path_input*)libinput;
        struct path_seat *seat;
-       struct evdev_device *device;
-       const char *devnode = input->path;
-       char *syspath;
-       int fd;
-
-       if (input->device)
-               return 0;
-
-       fd = open_restricted(libinput, input->path, O_RDWR|O_NONBLOCK);
-       if (fd < 0) {
-               log_info("opening input device '%s' failed.\n", devnode);
-               return -1;
+       struct evdev_device *device = NULL;
+       char *sysname = NULL, *syspath = NULL;
+       char *seat_name = NULL, *seat_logical_name = NULL;
+
+       if (path_get_udev_properties(devnode, &sysname, &syspath,
+                                    &seat_name, &seat_logical_name) == -1) {
+               log_info(&input->base,
+                        "failed to obtain sysname for device '%s'.\n",
+                        devnode);
+               return NULL;
        }
 
-       syspath = path_get_sysname(devnode);
-       if (!syspath) {
-               close_restricted(libinput, fd);
-               log_info("failed to obtain syspath for device '%s'.\n", devnode);
-               return -1;
+       seat = path_seat_get_named(input, seat_name, seat_logical_name);
+
+       if (seat) {
+               libinput_seat_ref(&seat->base);
+       } else {
+               seat = path_seat_create(input, seat_name, seat_logical_name);
+               if (!seat) {
+                       log_info(&input->base,
+                                "failed to create seat for device '%s'.\n",
+                                devnode);
+                       goto out;
+               }
        }
 
-       seat = path_seat_create(input);
-
-       device = evdev_device_create(&seat->base, devnode, syspath, fd);
-       free(syspath);
+       device = evdev_device_create(&seat->base, devnode, sysname, syspath);
+       libinput_seat_unref(&seat->base);
 
        if (device == EVDEV_UNHANDLED_DEVICE) {
-               close_restricted(libinput, fd);
-               log_info("not using input device '%s'.\n", devnode);
-               libinput_seat_unref(&seat->base);
-               return -1;
+               device = NULL;
+               log_info(&input->base,
+                        "not using input device '%s'.\n",
+                        devnode);
+               goto out;
        } else if (device == NULL) {
-               close_restricted(libinput, fd);
-               log_info("failed to create input device '%s'.\n", devnode);
-               libinput_seat_unref(&seat->base);
-               return -1;
+               log_info(&input->base,
+                        "failed to create input device '%s'.\n",
+                        devnode);
+               goto out;
        }
 
-       input->device = device;
+out:
+       free(sysname);
+       free(syspath);
+       free(seat_name);
+       free(seat_logical_name);
+
+       return device ? &device->base : NULL;
+}
+
+static int
+path_input_enable(struct libinput *libinput)
+{
+       struct path_input *input = (struct path_input*)libinput;
+       struct path_device *dev;
+
+       list_for_each(dev, &input->path_list, link) {
+               if (path_device_enable(input, dev->path) == NULL) {
+                       path_input_disable(libinput);
+                       return -1;
+               }
+       }
 
        return 0;
 }
@@ -158,7 +227,13 @@ static void
 path_input_destroy(struct libinput *input)
 {
        struct path_input *path_input = (struct path_input*)input;
-       free(path_input->path);
+       struct path_device *dev, *tmp;
+
+       list_for_each_safe(dev, tmp, &path_input->path_list, link) {
+               free(dev->path);
+               free(dev);
+       }
+
 }
 
 static const struct libinput_interface_backend interface_backend = {
@@ -168,13 +243,12 @@ static const struct libinput_interface_backend interface_backend = {
 };
 
 LIBINPUT_EXPORT struct libinput *
-libinput_create_from_path(const struct libinput_interface *interface,
-                         void *user_data,
-                         const char *path)
+libinput_path_create_context(const struct libinput_interface *interface,
+                            void *user_data)
 {
        struct path_input *input;
 
-       if (!interface || !path)
+       if (!interface)
                return NULL;
 
        input = zalloc(sizeof *input);
@@ -187,12 +261,72 @@ libinput_create_from_path(const struct libinput_interface *interface,
                return NULL;
        }
 
-       input->path = strdup(path);
+       list_init(&input->path_list);
+
+       return &input->base;
+}
 
-       if (path_input_enable(&input->base) < 0) {
-               libinput_destroy(&input->base);
+LIBINPUT_EXPORT struct libinput_device *
+libinput_path_add_device(struct libinput *libinput,
+                        const char *path)
+{
+       struct path_input *input = (struct path_input*)libinput;
+       struct path_device *dev;
+       struct libinput_device *device;
+
+       if (libinput->interface_backend != &interface_backend) {
+               log_bug_client(libinput, "Mismatching backends.\n");
                return NULL;
        }
 
-       return &input->base;
+       dev = zalloc(sizeof *dev);
+       if (!dev)
+               return NULL;
+
+       dev->path = strdup(path);
+       if (!dev->path) {
+               free(dev);
+               return NULL;
+       }
+
+       list_insert(&input->path_list, &dev->link);
+
+       device = path_device_enable(input, dev->path);
+
+       if (!device) {
+               list_remove(&dev->link);
+               free(dev->path);
+               free(dev);
+       }
+
+       return device;
+}
+
+LIBINPUT_EXPORT void
+libinput_path_remove_device(struct libinput_device *device)
+{
+       struct libinput *libinput = device->seat->libinput;
+       struct path_input *input = (struct path_input*)libinput;
+       struct libinput_seat *seat;
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct path_device *dev;
+
+       if (libinput->interface_backend != &interface_backend) {
+               log_bug_client(libinput, "Mismatching backends.\n");
+               return;
+       }
+
+       list_for_each(dev, &input->path_list, link) {
+               if (strcmp(evdev->devnode, dev->path) == 0) {
+                       list_remove(&dev->link);
+                       free(dev->path);
+                       free(dev);
+                       break;
+               }
+       }
+
+       seat = device->seat;
+       libinput_seat_ref(seat);
+       path_disable_device(libinput, evdev);
+       libinput_seat_unref(seat);
 }