X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-terminal%2Fidev-evdev.c;h=719e18c316e369bbb399bfea06fd1e0f1aeba56e;hp=be9b0301a4c81156a3476f541806e52c5e2e1a7f;hb=89febb631a4710992cd41e402a643451b19c11a7;hpb=2e1dd622ee7020a608c3397768ea245dcb6409d1 diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c index be9b0301a..719e18c31 100644 --- a/src/libsystemd-terminal/idev-evdev.c +++ b/src/libsystemd-terminal/idev-evdev.c @@ -49,6 +49,7 @@ struct idev_evdev { bool unsync : 1; /* not in-sync with kernel */ bool resync : 1; /* re-syncing with kernel */ + bool running : 1; }; struct unmanaged_evdev { @@ -101,7 +102,16 @@ static void idev_evdev_name(char *out, dev_t devnum) { sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum)); } -static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) { +static int idev_evdev_feed_resync(idev_evdev *evdev) { + idev_data data = { + .type = IDEV_DATA_RESYNC, + .resync = evdev->resync, + }; + + return idev_element_feed(&evdev->element, &data); +} + +static int idev_evdev_feed_evdev(idev_evdev *evdev, struct input_event *event) { idev_data data = { .type = IDEV_DATA_EVDEV, .resync = evdev->resync, @@ -155,7 +165,6 @@ static int idev_evdev_io(idev_evdev *evdev) { * case we cannot keep up with the kernel. * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless * whether any event was synced afterwards. - * TODO: Forward SYN_DROPPED to attached devices. */ flags = LIBEVDEV_READ_FLAG_NORMAL; @@ -190,7 +199,7 @@ static int idev_evdev_io(idev_evdev *evdev) { } else if (r == LIBEVDEV_READ_STATUS_SYNC) { if (evdev->resync) { /* sync-event */ - r = idev_evdev_raise(evdev, &ev); + r = idev_evdev_feed_evdev(evdev, &ev); if (r != 0) { error = r; break; @@ -199,10 +208,15 @@ static int idev_evdev_io(idev_evdev *evdev) { /* start of sync */ evdev->resync = true; flags = LIBEVDEV_READ_FLAG_SYNC; + r = idev_evdev_feed_resync(evdev); + if (r != 0) { + error = r; + break; + } } } else { /* normal event */ - r = idev_evdev_raise(evdev, &ev); + r = idev_evdev_feed_evdev(evdev, &ev); if (r != 0) { error = r; break; @@ -268,6 +282,12 @@ static void idev_evdev_enable(idev_evdev *evdev) { assert(evdev->fd_src); assert(evdev->idle_src); + if (evdev->running) + return; + if (evdev->fd < 0 || evdev->element.n_open < 1 || !evdev->element.enabled) + return; + + evdev->running = true; sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON); sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT); } @@ -277,6 +297,11 @@ static void idev_evdev_disable(idev_evdev *evdev) { assert(evdev->fd_src); assert(evdev->idle_src); + if (!evdev->running) + return; + + evdev->running = false; + idev_evdev_feed_resync(evdev); sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); } @@ -288,9 +313,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { if (fd < 0 || evdev->fd == fd) { fd = -1; - if (evdev->fd >= 0 && e->n_open > 0 && e->enabled) - idev_evdev_enable(evdev); - + idev_evdev_enable(evdev); return 0; } @@ -307,18 +330,14 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { flags = fcntl(fd, F_GETFL, 0); if (flags < 0) - return r; + return -errno; flags &= O_ACCMODE; if (flags == O_WRONLY) return -EACCES; evdev->element.readable = true; - evdev->element.writable = true; - if (flags == O_RDONLY) - evdev->element.writable = false; - else if (flags == O_WRONLY) - evdev->element.readable = false; + evdev->element.writable = !(flags & O_RDONLY); /* * TODO: We *MUST* re-sync the device so we get a delta of the changed @@ -355,15 +374,14 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) { return r; } - if (e->n_open < 1 || !e->enabled) { - sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); - sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); - } + sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF); + sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF); evdev->unsync = true; evdev->fd = fd; - fd = -1; + + idev_evdev_enable(evdev); return 0; } @@ -375,12 +393,11 @@ static void idev_evdev_pause(idev_evdev *evdev, bool release) { log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name); + idev_evdev_disable(evdev); if (release) { evdev->idle_src = sd_event_source_unref(evdev->idle_src); evdev->fd_src = sd_event_source_unref(evdev->fd_src); evdev->fd = safe_close(evdev->fd); - } else { - idev_evdev_disable(evdev); } } @@ -858,7 +875,6 @@ static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_de int r; assert_return(s, -EINVAL); - assert_return(s->context->sysbus, -EINVAL); assert_return(s->managed, -EINVAL); assert_return(s->context->sysbus, -EINVAL); assert_return(ud, -EINVAL);