2013-12-10 13:20:36 +10:00
|
|
|
/*
|
2015-05-28 08:23:59 +10:00
|
|
|
* Copyright © 2013-2015 Red Hat, Inc.
|
2013-12-10 13:20:36 +10:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
2013-12-10 13:20:36 +10:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
2013-12-10 13:20:36 +10:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2014-01-29 16:37:45 +10:00
|
|
|
#include <errno.h>
|
2013-12-10 13:20:36 +10:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <string.h>
|
2015-06-23 11:31:56 +02:00
|
|
|
#include <sys/stat.h>
|
2013-12-10 13:20:36 +10:00
|
|
|
#include <libudev.h>
|
|
|
|
|
|
|
|
|
|
#include "evdev.h"
|
|
|
|
|
|
2019-06-06 14:25:21 +10:00
|
|
|
struct path_input {
|
|
|
|
|
struct libinput base;
|
|
|
|
|
struct udev *udev;
|
|
|
|
|
struct list path_list;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct path_device {
|
|
|
|
|
struct list link;
|
|
|
|
|
struct udev_device *udev_device;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct path_seat {
|
|
|
|
|
struct libinput_seat base;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 12:03:47 +10:00
|
|
|
static const char default_seat[] = "seat0";
|
|
|
|
|
static const char default_seat_name[] = "default";
|
|
|
|
|
|
2014-01-29 16:37:45 +10:00
|
|
|
static void
|
|
|
|
|
path_disable_device(struct libinput *libinput,
|
|
|
|
|
struct evdev_device *device)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
evdev_device_remove(device);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-10 13:20:36 +10:00
|
|
|
static void
|
|
|
|
|
path_input_disable(struct libinput *libinput)
|
|
|
|
|
{
|
|
|
|
|
struct path_input *input = (struct path_input*)libinput;
|
2014-01-29 15:57:53 +10:00
|
|
|
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,
|
2014-01-29 16:37:45 +10:00
|
|
|
&seat->base.devices_list, base.link)
|
|
|
|
|
path_disable_device(libinput, device);
|
2014-01-29 15:57:53 +10:00
|
|
|
libinput_seat_unref(&seat->base);
|
2013-12-10 13:20:36 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
path_seat_destroy(struct libinput_seat *seat)
|
|
|
|
|
{
|
|
|
|
|
struct path_seat *pseat = (struct path_seat*)seat;
|
|
|
|
|
free(pseat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct path_seat*
|
2014-01-21 12:03:47 +10:00
|
|
|
path_seat_create(struct path_input *input,
|
|
|
|
|
const char *seat_name,
|
|
|
|
|
const char *seat_logical_name)
|
2013-12-10 13:20:36 +10:00
|
|
|
{
|
|
|
|
|
struct path_seat *seat;
|
|
|
|
|
|
|
|
|
|
seat = zalloc(sizeof(*seat));
|
|
|
|
|
|
2014-01-21 12:03:47 +10:00
|
|
|
libinput_seat_init(&seat->base, &input->base, seat_name,
|
|
|
|
|
seat_logical_name, path_seat_destroy);
|
2013-12-10 13:20:36 +10:00
|
|
|
|
|
|
|
|
return seat;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 15:57:53 +10:00
|
|
|
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) {
|
2015-05-26 08:46:05 +10:00
|
|
|
if (streq(seat->base.physical_name, seat_name_physical) &&
|
|
|
|
|
streq(seat->base.logical_name, seat_name_logical))
|
2014-01-29 15:57:53 +10:00
|
|
|
return seat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct libinput_device *
|
2014-11-20 13:50:57 +10:00
|
|
|
path_device_enable(struct path_input *input,
|
2014-11-19 14:16:48 +10:00
|
|
|
struct udev_device *udev_device,
|
|
|
|
|
const char *seat_logical_name_override)
|
2013-12-10 13:20:36 +10:00
|
|
|
{
|
|
|
|
|
struct path_seat *seat;
|
2014-01-29 15:57:53 +10:00
|
|
|
struct evdev_device *device = NULL;
|
2014-02-21 22:17:17 +01:00
|
|
|
char *seat_name = NULL, *seat_logical_name = NULL;
|
2017-02-09 09:43:54 +10:00
|
|
|
const char *seat_prop, *output_name;
|
2017-02-13 14:17:52 +10:00
|
|
|
const char *devnode, *sysname;
|
2013-12-10 13:20:36 +10:00
|
|
|
|
2014-11-19 14:16:48 +10:00
|
|
|
devnode = udev_device_get_devnode(udev_device);
|
2017-02-13 14:17:52 +10:00
|
|
|
sysname = udev_device_get_sysname(udev_device);
|
2014-11-19 14:16:48 +10:00
|
|
|
|
2014-11-20 13:50:57 +10:00
|
|
|
seat_prop = udev_device_get_property_value(udev_device, "ID_SEAT");
|
2017-07-07 09:47:06 +10:00
|
|
|
seat_name = safe_strdup(seat_prop ? seat_prop : default_seat);
|
2014-11-20 13:50:57 +10:00
|
|
|
|
2014-11-19 14:16:48 +10:00
|
|
|
if (seat_logical_name_override) {
|
2017-07-07 09:47:06 +10:00
|
|
|
seat_logical_name = safe_strdup(seat_logical_name_override);
|
2014-11-19 14:16:48 +10:00
|
|
|
} else {
|
|
|
|
|
seat_prop = udev_device_get_property_value(udev_device, "WL_SEAT");
|
|
|
|
|
seat_logical_name = strdup(seat_prop ? seat_prop : default_seat_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!seat_logical_name) {
|
|
|
|
|
log_error(&input->base,
|
2017-02-13 14:17:52 +10:00
|
|
|
"%s: failed to create seat name for device '%s'.\n",
|
|
|
|
|
sysname,
|
2014-11-19 14:16:48 +10:00
|
|
|
devnode);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2013-12-10 13:20:36 +10:00
|
|
|
|
2014-01-29 15:57:53 +10:00
|
|
|
seat = path_seat_get_named(input, seat_name, seat_logical_name);
|
2013-12-10 13:20:36 +10:00
|
|
|
|
2014-01-29 15:57:53 +10:00
|
|
|
if (seat) {
|
|
|
|
|
libinput_seat_ref(&seat->base);
|
|
|
|
|
} else {
|
|
|
|
|
seat = path_seat_create(input, seat_name, seat_logical_name);
|
|
|
|
|
if (!seat) {
|
2014-06-18 19:51:19 +10:00
|
|
|
log_info(&input->base,
|
2017-02-13 14:17:52 +10:00
|
|
|
"%s: failed to create seat for device '%s'.\n",
|
|
|
|
|
sysname,
|
2014-06-18 19:51:19 +10:00
|
|
|
devnode);
|
2014-01-29 15:57:53 +10:00
|
|
|
goto out;
|
|
|
|
|
}
|
2014-01-29 16:08:54 +10:00
|
|
|
}
|
|
|
|
|
|
2014-11-20 13:55:48 +10:00
|
|
|
device = evdev_device_create(&seat->base, udev_device);
|
2014-01-22 23:48:39 +01:00
|
|
|
libinput_seat_unref(&seat->base);
|
2013-12-10 13:20:36 +10:00
|
|
|
|
|
|
|
|
if (device == EVDEV_UNHANDLED_DEVICE) {
|
2014-01-29 15:57:53 +10:00
|
|
|
device = NULL;
|
2014-06-18 19:51:19 +10:00
|
|
|
log_info(&input->base,
|
2017-02-13 14:17:52 +10:00
|
|
|
"%-7s - not using input device '%s'.\n",
|
|
|
|
|
sysname,
|
2014-06-18 19:51:19 +10:00
|
|
|
devnode);
|
2014-01-29 15:57:53 +10:00
|
|
|
goto out;
|
2013-12-10 13:20:36 +10:00
|
|
|
} else if (device == NULL) {
|
2014-06-18 19:51:19 +10:00
|
|
|
log_info(&input->base,
|
2017-02-13 14:17:52 +10:00
|
|
|
"%-7s - failed to create input device '%s'.\n",
|
|
|
|
|
sysname,
|
2014-06-18 19:51:19 +10:00
|
|
|
devnode);
|
2014-01-29 15:57:53 +10:00
|
|
|
goto out;
|
2013-12-10 13:20:36 +10:00
|
|
|
}
|
|
|
|
|
|
2016-11-25 13:58:39 +10:00
|
|
|
evdev_read_calibration_prop(device);
|
2017-02-09 09:43:54 +10:00
|
|
|
output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
|
2017-07-07 09:47:06 +10:00
|
|
|
device->output_name = safe_strdup(output_name);
|
2016-11-25 13:58:39 +10:00
|
|
|
|
2014-01-29 15:57:53 +10:00
|
|
|
out:
|
|
|
|
|
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) {
|
2014-11-19 14:16:48 +10:00
|
|
|
if (path_device_enable(input, dev->udev_device, NULL) == NULL) {
|
2014-01-29 15:57:53 +10:00
|
|
|
path_input_disable(libinput);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-10 13:20:36 +10:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
path_input_destroy(struct libinput *input)
|
|
|
|
|
{
|
|
|
|
|
struct path_input *path_input = (struct path_input*)input;
|
2014-01-29 15:57:53 +10:00
|
|
|
struct path_device *dev, *tmp;
|
|
|
|
|
|
2014-11-20 13:36:32 +10:00
|
|
|
udev_unref(path_input->udev);
|
|
|
|
|
|
2014-01-29 15:57:53 +10:00
|
|
|
list_for_each_safe(dev, tmp, &path_input->path_list, link) {
|
2014-11-20 13:50:57 +10:00
|
|
|
udev_device_unref(dev->udev_device);
|
2014-01-29 15:57:53 +10:00
|
|
|
free(dev);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-10 13:20:36 +10:00
|
|
|
}
|
|
|
|
|
|
2014-11-19 15:26:40 +10:00
|
|
|
static struct libinput_device *
|
|
|
|
|
path_create_device(struct libinput *libinput,
|
2014-11-19 14:16:48 +10:00
|
|
|
struct udev_device *udev_device,
|
|
|
|
|
const char *seat_name)
|
2014-11-19 15:26:40 +10:00
|
|
|
{
|
|
|
|
|
struct path_input *input = (struct path_input*)libinput;
|
|
|
|
|
struct path_device *dev;
|
|
|
|
|
struct libinput_device *device;
|
|
|
|
|
|
|
|
|
|
dev = zalloc(sizeof *dev);
|
2014-11-20 13:50:57 +10:00
|
|
|
dev->udev_device = udev_device_ref(udev_device);
|
2014-11-19 15:26:40 +10:00
|
|
|
|
|
|
|
|
list_insert(&input->path_list, &dev->link);
|
|
|
|
|
|
2014-11-19 14:16:48 +10:00
|
|
|
device = path_device_enable(input, udev_device, seat_name);
|
2014-11-19 15:26:40 +10:00
|
|
|
|
|
|
|
|
if (!device) {
|
2014-11-20 13:50:57 +10:00
|
|
|
udev_device_unref(dev->udev_device);
|
2014-11-19 15:26:40 +10:00
|
|
|
list_remove(&dev->link);
|
|
|
|
|
free(dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return device;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-19 13:43:59 +10:00
|
|
|
static int
|
|
|
|
|
path_device_change_seat(struct libinput_device *device,
|
|
|
|
|
const char *seat_name)
|
|
|
|
|
{
|
|
|
|
|
struct libinput *libinput = device->seat->libinput;
|
2017-01-30 19:48:33 +10:00
|
|
|
struct evdev_device *evdev = evdev_device(device);
|
2014-11-19 13:43:59 +10:00
|
|
|
struct udev_device *udev_device = NULL;
|
|
|
|
|
int rc = -1;
|
|
|
|
|
|
2017-01-30 19:48:33 +10:00
|
|
|
udev_device = evdev->udev_device;
|
2014-11-19 13:43:59 +10:00
|
|
|
udev_device_ref(udev_device);
|
|
|
|
|
libinput_path_remove_device(device);
|
|
|
|
|
|
|
|
|
|
if (path_create_device(libinput, udev_device, seat_name) != NULL)
|
|
|
|
|
rc = 0;
|
|
|
|
|
udev_device_unref(udev_device);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-10 13:20:36 +10:00
|
|
|
static const struct libinput_interface_backend interface_backend = {
|
|
|
|
|
.resume = path_input_enable,
|
|
|
|
|
.suspend = path_input_disable,
|
|
|
|
|
.destroy = path_input_destroy,
|
2014-11-19 13:43:59 +10:00
|
|
|
.device_change_seat = path_device_change_seat,
|
2013-12-10 13:20:36 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LIBINPUT_EXPORT struct libinput *
|
2014-01-29 15:38:48 +10:00
|
|
|
libinput_path_create_context(const struct libinput_interface *interface,
|
|
|
|
|
void *user_data)
|
2013-12-10 13:20:36 +10:00
|
|
|
{
|
|
|
|
|
struct path_input *input;
|
2014-11-20 13:36:32 +10:00
|
|
|
struct udev *udev;
|
2013-12-10 13:20:36 +10:00
|
|
|
|
2014-01-29 15:38:48 +10:00
|
|
|
if (!interface)
|
2013-12-10 13:20:36 +10:00
|
|
|
return NULL;
|
|
|
|
|
|
2014-11-20 13:36:32 +10:00
|
|
|
udev = udev_new();
|
|
|
|
|
if (!udev)
|
2013-12-10 13:20:36 +10:00
|
|
|
return NULL;
|
|
|
|
|
|
2014-11-20 13:36:32 +10:00
|
|
|
input = zalloc(sizeof *input);
|
2017-07-07 09:42:59 +10:00
|
|
|
if (libinput_init(&input->base, interface,
|
2013-12-10 13:20:36 +10:00
|
|
|
&interface_backend, user_data) != 0) {
|
2014-11-20 13:36:32 +10:00
|
|
|
udev_unref(udev);
|
2013-12-10 13:20:36 +10:00
|
|
|
free(input);
|
2014-01-29 15:57:53 +10:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-20 13:36:32 +10:00
|
|
|
input->udev = udev;
|
2014-01-29 15:57:53 +10:00
|
|
|
list_init(&input->path_list);
|
|
|
|
|
|
2013-12-10 13:20:36 +10:00
|
|
|
return &input->base;
|
|
|
|
|
}
|
2014-01-29 16:37:45 +10:00
|
|
|
|
2014-11-20 13:50:57 +10:00
|
|
|
static inline struct udev_device *
|
2015-02-03 14:18:15 +10:00
|
|
|
udev_device_from_devnode(struct libinput *libinput,
|
|
|
|
|
struct udev *udev,
|
|
|
|
|
const char *devnode)
|
2014-11-20 13:50:57 +10:00
|
|
|
{
|
2015-02-03 14:18:15 +10:00
|
|
|
struct udev_device *dev;
|
2014-11-20 13:50:57 +10:00
|
|
|
struct stat st;
|
2015-02-03 14:18:15 +10:00
|
|
|
size_t count = 0;
|
2014-11-20 13:50:57 +10:00
|
|
|
|
|
|
|
|
if (stat(devnode, &st) < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2015-02-03 14:18:15 +10:00
|
|
|
dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
|
|
|
|
|
|
|
|
|
|
while (dev && !udev_device_get_is_initialized(dev)) {
|
|
|
|
|
udev_device_unref(dev);
|
|
|
|
|
count++;
|
2015-07-22 10:44:44 +10:00
|
|
|
if (count > 200) {
|
2015-02-03 14:18:15 +10:00
|
|
|
log_bug_libinput(libinput,
|
|
|
|
|
"udev device never initialized (%s)\n",
|
|
|
|
|
devnode);
|
2018-01-05 14:30:21 +10:00
|
|
|
return NULL;
|
2015-02-03 14:18:15 +10:00
|
|
|
}
|
2018-11-01 16:19:20 +10:00
|
|
|
msleep(10);
|
|
|
|
|
dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
|
2015-02-03 14:18:15 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dev;
|
2014-11-20 13:50:57 +10:00
|
|
|
}
|
|
|
|
|
|
2014-01-29 16:37:45 +10:00
|
|
|
LIBINPUT_EXPORT struct libinput_device *
|
|
|
|
|
libinput_path_add_device(struct libinput *libinput,
|
|
|
|
|
const char *path)
|
|
|
|
|
{
|
2014-11-20 13:50:57 +10:00
|
|
|
struct path_input *input = (struct path_input *)libinput;
|
|
|
|
|
struct udev *udev = input->udev;
|
|
|
|
|
struct udev_device *udev_device;
|
|
|
|
|
struct libinput_device *device;
|
|
|
|
|
|
2019-02-08 11:08:36 +10:00
|
|
|
if (strlen(path) > PATH_MAX) {
|
|
|
|
|
log_bug_client(libinput,
|
|
|
|
|
"Unexpected path, limited to %d characters.\n",
|
|
|
|
|
PATH_MAX);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 16:37:45 +10:00
|
|
|
if (libinput->interface_backend != &interface_backend) {
|
2014-06-18 19:51:19 +10:00
|
|
|
log_bug_client(libinput, "Mismatching backends.\n");
|
2014-01-29 16:37:45 +10:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 11:46:31 +10:00
|
|
|
/* We cannot do this during path_create_context because the log
|
|
|
|
|
* handler isn't set up there but we really want to log to the right
|
|
|
|
|
* place if the quirks run into parser errors. So we have to do it
|
|
|
|
|
* on the first call to add_device.
|
|
|
|
|
*/
|
|
|
|
|
libinput_init_quirks(libinput);
|
|
|
|
|
|
2015-02-03 14:18:15 +10:00
|
|
|
udev_device = udev_device_from_devnode(libinput, udev, path);
|
2014-11-20 13:50:57 +10:00
|
|
|
if (!udev_device) {
|
|
|
|
|
log_bug_client(libinput, "Invalid path %s\n", path);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-27 16:08:04 +08:00
|
|
|
if (ignore_litest_test_suite_device(udev_device)) {
|
|
|
|
|
udev_device_unref(udev_device);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-19 14:16:48 +10:00
|
|
|
device = path_create_device(libinput, udev_device, NULL);
|
2014-11-20 13:50:57 +10:00
|
|
|
udev_device_unref(udev_device);
|
|
|
|
|
return device;
|
2014-01-29 16:37:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2017-01-30 19:48:33 +10:00
|
|
|
struct evdev_device *evdev = evdev_device(device);
|
2014-01-29 16:37:45 +10:00
|
|
|
struct path_device *dev;
|
|
|
|
|
|
|
|
|
|
if (libinput->interface_backend != &interface_backend) {
|
2014-06-18 19:51:19 +10:00
|
|
|
log_bug_client(libinput, "Mismatching backends.\n");
|
2014-01-29 16:37:45 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_for_each(dev, &input->path_list, link) {
|
2014-11-20 13:55:48 +10:00
|
|
|
if (dev->udev_device == evdev->udev_device) {
|
2014-01-29 16:37:45 +10:00
|
|
|
list_remove(&dev->link);
|
2014-11-20 13:50:57 +10:00
|
|
|
udev_device_unref(dev->udev_device);
|
2014-01-29 16:37:45 +10:00
|
|
|
free(dev);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seat = device->seat;
|
|
|
|
|
libinput_seat_ref(seat);
|
|
|
|
|
path_disable_device(libinput, evdev);
|
|
|
|
|
libinput_seat_unref(seat);
|
|
|
|
|
}
|