[PATCH 8/9] evdev: add hotplug support
Tiago Vignatti
tiago.vignatti at intel.com
Mon Oct 24 07:42:21 PDT 2011
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
compositor/evdev.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 106 insertions(+), 6 deletions(-)
diff --git a/compositor/evdev.c b/compositor/evdev.c
index b81e513..18ebe04 100644
--- a/compositor/evdev.c
+++ b/compositor/evdev.c
@@ -34,6 +34,8 @@
struct evdev_input {
struct wlsc_input_device base;
+ struct wl_list devices_list;
+ struct udev_monitor *udev_monitor;
};
/* Event queue used to defer keyboard/button events until EV_SYN time. */
@@ -49,6 +51,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 +65,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;
@@ -384,8 +388,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
@@ -473,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 =
@@ -483,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;
@@ -490,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;
}
@@ -500,15 +510,101 @@ 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 void
+device_added(struct udev_device *udev_device, struct evdev_input *master)
+{
+ struct wlsc_compositor *c =
+ (struct wlsc_compositor *) master->base.input_device.compositor;
+
+ const char *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 const char default_seat[] = "seat0";
+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)
@@ -527,6 +623,12 @@ 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);
+ if (!evdev_config_udev_monitor(udev, input)) {
+ free(input);
+ return;
+ }
+
e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "input");
udev_enumerate_scan_devices(e);
@@ -542,10 +644,8 @@ evdev_input_add_devices(struct wlsc_compositor *c,
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));
- }
+ if (strcmp(device_seat, seat) == 0)
+ device_added(device, input);
udev_device_unref(device);
}
--
1.7.5.4
More information about the wayland-devel
mailing list