1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <libevdev/libevdev.h>
28 #include <systemd/sd-bus.h>
29 #include <systemd/sd-event.h>
34 #include "idev-internal.h"
36 #include "udev-util.h"
39 typedef struct idev_evdev idev_evdev;
40 typedef struct unmanaged_evdev unmanaged_evdev;
41 typedef struct managed_evdev managed_evdev;
44 struct idev_element element;
45 struct libevdev *evdev;
47 sd_event_source *fd_src;
48 sd_event_source *idle_src;
50 bool unsync : 1; /* not in-sync with kernel */
51 bool resync : 1; /* re-syncing with kernel */
54 struct unmanaged_evdev {
55 struct idev_evdev evdev;
59 struct managed_evdev {
60 struct idev_evdev evdev;
63 sd_bus_slot *slot_pause_device;
64 sd_bus_slot *slot_resume_device;
65 sd_bus_slot *slot_take_device;
67 bool requested : 1; /* TakeDevice() was sent */
68 bool acquired : 1; /* TakeDevice() was successful */
71 #define idev_evdev_from_element(_e) container_of((_e), idev_evdev, element)
72 #define unmanaged_evdev_from_element(_e) \
73 container_of(idev_evdev_from_element(_e), unmanaged_evdev, evdev)
74 #define managed_evdev_from_element(_e) \
75 container_of(idev_evdev_from_element(_e), managed_evdev, evdev)
77 #define IDEV_EVDEV_INIT(_vtable, _session) ((idev_evdev){ \
78 .element = IDEV_ELEMENT_INIT((_vtable), (_session)), \
82 #define IDEV_EVDEV_NAME_MAX (8 + DECIMAL_STR_MAX(unsigned) * 2)
84 static const idev_element_vtable unmanaged_evdev_vtable;
85 static const idev_element_vtable managed_evdev_vtable;
87 static int idev_evdev_resume(idev_evdev *evdev, int dev_fd);
88 static void idev_evdev_pause(idev_evdev *evdev, bool release);
91 * Virtual Evdev Element
92 * The virtual evdev element is the base class of all other evdev elements. It
93 * uses libevdev to access the kernel evdev API. It supports asynchronous
94 * access revocation, re-syncing if events got dropped and more.
95 * This element cannot be used by itself. There must be a wrapper around it
96 * which opens a file-descriptor and passes it to the virtual evdev element.
99 static void idev_evdev_name(char *out, dev_t devnum) {
100 /* @out must be at least of size IDEV_EVDEV_NAME_MAX */
101 sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum));
104 static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) {
106 .type = IDEV_DATA_EVDEV,
107 .resync = evdev->resync,
113 return idev_element_feed(&evdev->element, &data);
116 static void idev_evdev_hup(idev_evdev *evdev) {
118 * On HUP, we close the current fd via idev_evdev_pause(). This drops
119 * the event-sources from the main-loop and effectively puts the
120 * element asleep. If the HUP is part of a hotplug-event, a following
121 * udev-notification will destroy the element. Otherwise, the HUP is
122 * either result of access-revokation or a serious error.
123 * For unmanaged devices, we should never receive HUP (except for
124 * unplug-events). But if we do, something went seriously wrong and we
125 * shouldn't try to be clever.
126 * Instead, we simply stay asleep and wait for the device to be
127 * disabled and then re-enabled (or closed and re-opened). This will
128 * re-open the device node and restart the device.
129 * For managed devices, a HUP usually means our device-access was
130 * revoked. In that case, we simply put the device asleep and wait for
131 * logind to notify us once the device is alive again. logind also
132 * passes us a new fd. Hence, we don't have to re-enable the device.
134 * Long story short: The only thing we have to do here, is close() the
135 * file-descriptor and remove it from the main-loop. Everything else is
136 * handled via additional events we receive.
139 idev_evdev_pause(evdev, true);
142 static int idev_evdev_io(idev_evdev *evdev) {
143 idev_element *e = &evdev->element;
144 struct input_event ev;
149 * Read input-events via libevdev until the input-queue is drained. In
150 * case we're disabled, don't do anything. The input-queue might
151 * overflow, but we don't care as we have to resync after wake-up,
153 * TODO: libevdev should give us a hint how many events to read. We
154 * really want to avoid starvation, so we shouldn't read forever in
155 * case we cannot keep up with the kernel.
156 * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless
157 * whether any event was synced afterwards.
158 * TODO: Forward SYN_DROPPED to attached devices.
161 flags = LIBEVDEV_READ_FLAG_NORMAL;
164 /* immediately resync, even if in sync right now */
165 evdev->unsync = false;
166 evdev->resync = false;
167 flags = LIBEVDEV_READ_FLAG_NORMAL;
168 r = libevdev_next_event(evdev->evdev, flags | LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
169 if (r < 0 && r != -EAGAIN) {
172 } else if (r != LIBEVDEV_READ_STATUS_SYNC) {
173 log_debug("idev-evdev: %s/%s: cannot force resync: %d",
174 e->session->name, e->name, r);
177 r = libevdev_next_event(evdev->evdev, flags, &ev);
180 if (evdev->resync && r == -EAGAIN) {
182 evdev->resync = false;
183 flags = LIBEVDEV_READ_FLAG_NORMAL;
184 } else if (r == -EAGAIN) {
185 /* no data available */
190 } else if (r == LIBEVDEV_READ_STATUS_SYNC) {
193 r = idev_evdev_raise(evdev, &ev);
200 evdev->resync = true;
201 flags = LIBEVDEV_READ_FLAG_SYNC;
205 r = idev_evdev_raise(evdev, &ev);
214 log_debug("idev-evdev: %s/%s: error on data event: %s",
215 e->session->name, e->name, strerror(-error));
219 idev_evdev_hup(evdev);
223 static int idev_evdev_event_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
224 idev_evdev *evdev = userdata;
226 /* fetch data as long as EPOLLIN is signalled */
227 if (revents & EPOLLIN)
228 return idev_evdev_io(evdev);
230 if (revents & (EPOLLHUP | EPOLLERR))
231 idev_evdev_hup(evdev);
236 static int idev_evdev_idle_fn(sd_event_source *s, void *userdata) {
237 idev_evdev *evdev = userdata;
240 * The idle-event is raised whenever we have to re-sync the libevdev
241 * state from the kernel. We simply call into idev_evdev_io() which
242 * flushes the state and re-syncs it if @unsync is set.
243 * State has to be synced whenever our view of the kernel device is
244 * out of date. This is the case when we open the device, if the
245 * kernel's receive buffer overflows, or on other exceptional
246 * situations. Events during re-syncs must be forwarded to the upper
247 * layers so they can update their view of the device. However, such
248 * events must only be handled passively, as they might be out-of-order
249 * and/or re-ordered. Therefore, we mark them as 'sync' events.
255 return idev_evdev_io(evdev);
258 static void idev_evdev_destroy(idev_evdev *evdev) {
260 assert(evdev->fd < 0);
262 libevdev_free(evdev->evdev);
266 static void idev_evdev_enable(idev_evdev *evdev) {
268 assert(evdev->fd_src);
269 assert(evdev->idle_src);
271 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON);
272 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT);
275 static void idev_evdev_disable(idev_evdev *evdev) {
277 assert(evdev->fd_src);
278 assert(evdev->idle_src);
280 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
281 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
284 static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
285 idev_element *e = &evdev->element;
286 _cleanup_close_ int fd = dev_fd;
289 if (fd < 0 || evdev->fd == fd) {
291 if (evdev->fd >= 0 && e->n_open > 0 && e->enabled)
292 idev_evdev_enable(evdev);
297 idev_evdev_pause(evdev, true);
298 log_debug("idev-evdev: %s/%s: resume", e->session->name, e->name);
300 r = fd_nonblock(fd, true);
304 r = fd_cloexec(fd, true);
308 flags = fcntl(fd, F_GETFL, 0);
313 if (flags == O_WRONLY)
316 evdev->element.readable = true;
317 evdev->element.writable = true;
318 if (flags == O_RDONLY)
319 evdev->element.writable = false;
320 else if (flags == O_WRONLY)
321 evdev->element.readable = false;
324 * TODO: We *MUST* re-sync the device so we get a delta of the changed
325 * state while we didn't read events from the device. This works just
326 * fine with libevdev_change_fd(), however, libevdev_new_from_fd() (or
327 * libevdev_set_fd()) don't pass us events for the initial device
328 * state. So even if we force a re-sync, we will not get the delta for
329 * the initial device state.
330 * We really need to fix libevdev to support that!
333 r = libevdev_change_fd(evdev->evdev, fd);
335 r = libevdev_new_from_fd(fd, &evdev->evdev);
340 r = sd_event_add_io(e->session->context->event,
343 EPOLLHUP | EPOLLERR | EPOLLIN,
349 r = sd_event_add_defer(e->session->context->event,
354 evdev->fd_src = sd_event_source_unref(evdev->fd_src);
358 if (e->n_open < 1 || !e->enabled) {
359 sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
360 sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
363 evdev->unsync = true;
370 static void idev_evdev_pause(idev_evdev *evdev, bool release) {
371 idev_element *e = &evdev->element;
376 log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name);
379 evdev->idle_src = sd_event_source_unref(evdev->idle_src);
380 evdev->fd_src = sd_event_source_unref(evdev->fd_src);
381 evdev->fd = safe_close(evdev->fd);
383 idev_evdev_disable(evdev);
388 * Unmanaged Evdev Element
389 * The unmanaged evdev element opens the evdev node for a given input device
390 * directly (/dev/input/eventX) and thus needs sufficient privileges. It opens
391 * the device only if we really require it and releases it as soon as we're
392 * disabled or closed.
393 * The unmanaged element can be used in all situations where you have direct
394 * access to input device nodes. Unlike managed evdev elements, it can be used
395 * outside of user sessions and in emergency situations where logind is not
399 static void unmanaged_evdev_resume(idev_element *e) {
400 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
404 * Unmanaged devices can be acquired on-demand. Therefore, don't
405 * acquire it unless someone opened the device *and* we're enabled.
407 if (e->n_open < 1 || !e->enabled)
412 fd = open(eu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
414 if (errno != EACCES && errno != EPERM) {
415 log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
416 e->session->name, e->name, eu->devnode);
420 fd = open(eu->devnode, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
422 log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
423 e->session->name, e->name, eu->devnode);
435 r = idev_evdev_resume(&eu->evdev, fd);
437 log_debug("idev-evdev: %s/%s: cannot resume: %s",
438 e->session->name, e->name, strerror(-r));
441 static void unmanaged_evdev_pause(idev_element *e) {
442 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
445 * Release the device if the device is disabled or there is no-one who
446 * opened it. This guarantees we stay only available if we're opened
450 idev_evdev_pause(&eu->evdev, true);
453 static int unmanaged_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
454 _cleanup_(idev_element_freep) idev_element *e = NULL;
455 char name[IDEV_EVDEV_NAME_MAX];
461 assert_return(s, -EINVAL);
462 assert_return(ud, -EINVAL);
464 devnode = udev_device_get_devnode(ud);
465 devnum = udev_device_get_devnum(ud);
466 if (!devnode || devnum == 0)
469 idev_evdev_name(name, devnum);
471 eu = new0(unmanaged_evdev, 1);
475 e = &eu->evdev.element;
476 eu->evdev = IDEV_EVDEV_INIT(&unmanaged_evdev_vtable, s);
478 eu->devnode = strdup(devnode);
482 r = idev_element_add(e, name);
492 static void unmanaged_evdev_free(idev_element *e) {
493 unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
495 idev_evdev_destroy(&eu->evdev);
500 static const idev_element_vtable unmanaged_evdev_vtable = {
501 .free = unmanaged_evdev_free,
502 .enable = unmanaged_evdev_resume,
503 .disable = unmanaged_evdev_pause,
504 .open = unmanaged_evdev_resume,
505 .close = unmanaged_evdev_pause,
509 * Managed Evdev Element
510 * The managed evdev element uses systemd-logind to acquire evdev devices. This
511 * means, we do not open the device node /dev/input/eventX directly. Instead,
512 * logind passes us a file-descriptor whenever our session is activated. Thus,
513 * we don't need access to the device node directly.
514 * Furthermore, whenever the session is put asleep, logind revokes the
515 * file-descriptor so we loose access to the device.
516 * Managed evdev elements should be preferred over unmanaged elements whenever
517 * you run inside a user session with exclusive device access.
520 static int managed_evdev_take_device_fn(sd_bus *bus,
521 sd_bus_message *reply,
523 sd_bus_error *ret_error) {
524 managed_evdev *em = userdata;
525 idev_element *e = &em->evdev.element;
526 idev_session *s = e->session;
529 em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
531 if (sd_bus_message_is_method_error(reply, NULL)) {
532 const sd_bus_error *error = sd_bus_message_get_error(reply);
534 log_debug("idev-evdev: %s/%s: TakeDevice failed: %s: %s",
535 s->name, e->name, error->name, error->message);
541 r = sd_bus_message_read(reply, "hb", &fd, &paused);
543 log_debug("idev-evdev: %s/%s: erroneous TakeDevice reply", s->name, e->name);
547 /* If the device is paused, ignore it; we will get the next fd via
548 * ResumeDevice signals. */
552 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
554 log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name);
558 r = idev_evdev_resume(&em->evdev, fd);
560 log_debug("idev-evdev: %s/%s: cannot resume: %s",
561 s->name, e->name, strerror(-r));
566 static void managed_evdev_resume(idev_element *e) {
567 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
568 managed_evdev *em = managed_evdev_from_element(e);
569 idev_session *s = e->session;
570 idev_context *c = s->context;
574 * Acquiring managed devices is heavy, so do it only once we're
575 * enabled *and* opened by someone.
577 if (e->n_open < 1 || !e->enabled)
580 /* bail out if already pending */
584 r = sd_bus_message_new_method_call(c->sysbus,
586 "org.freedesktop.login1",
588 "org.freedesktop.login1.Session",
593 r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
597 r = sd_bus_call_async(c->sysbus,
598 &em->slot_take_device,
600 managed_evdev_take_device_fn,
606 em->requested = true;
610 log_debug("idev-evdev: %s/%s: cannot send TakeDevice request: %s",
611 s->name, e->name, strerror(-r));
614 static void managed_evdev_pause(idev_element *e) {
615 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
616 managed_evdev *em = managed_evdev_from_element(e);
617 idev_session *s = e->session;
618 idev_context *c = s->context;
622 * Releasing managed devices is heavy. Once acquired, we get
623 * notifications for sleep/wake-up events, so there's no reason to
624 * release it if disabled but opened. However, if a device is closed,
625 * we release it immediately as we don't care for sleep/wake-up events
626 * then (even if we're actually enabled).
629 idev_evdev_pause(&em->evdev, false);
631 if (e->n_open > 0 || !em->requested)
635 * If TakeDevice() is pending or was successful, make sure to
636 * release the device again. We don't care for return-values,
637 * so send it without waiting or callbacks.
638 * If a failed TakeDevice() is pending, but someone else took
639 * the device on the same bus-connection, we might incorrectly
640 * release their device. This is an unlikely race, though.
641 * Furthermore, you really shouldn't have two users of the
642 * controller-API on the same session, on the same devices, *AND* on
643 * the same bus-connection. So we don't care for that race..
646 idev_evdev_pause(&em->evdev, true);
647 em->requested = false;
649 if (!em->acquired && !em->slot_take_device)
652 em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
653 em->acquired = false;
655 r = sd_bus_message_new_method_call(c->sysbus,
657 "org.freedesktop.login1",
659 "org.freedesktop.login1.Session",
662 r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
664 r = sd_bus_send(c->sysbus, m, NULL);
667 if (r < 0 && r != -ENOTCONN)
668 log_debug("idev-evdev: %s/%s: cannot send ReleaseDevice: %s",
669 s->name, e->name, strerror(-r));
672 static int managed_evdev_pause_device_fn(sd_bus *bus,
673 sd_bus_message *signal,
675 sd_bus_error *ret_error) {
676 managed_evdev *em = userdata;
677 idev_element *e = &em->evdev.element;
678 idev_session *s = e->session;
679 idev_context *c = s->context;
680 uint32_t major, minor;
685 * We get PauseDevice() signals from logind whenever a device we
686 * requested was, or is about to be, paused. Arguments are major/minor
687 * number of the device and the mode of the operation.
688 * In case the event is not about our device, we ignore it. Otherwise,
689 * we treat it as asynchronous access-revocation (as if we got HUP on
690 * the device fd). Note that we might have already treated the HUP
691 * event via EPOLLHUP, whichever comes first.
693 * @mode can be one of the following:
694 * "pause": The device is about to be paused. We must react
695 * immediately and respond with PauseDeviceComplete(). Once
696 * we replied, logind will pause the device. Note that
697 * logind might apply any kind of timeout and force pause
698 * the device if we don't respond in a timely manner. In
699 * this case, we will receive a second PauseDevice event
700 * with @mode set to "force" (or similar).
701 * "force": The device was disabled forecfully by logind. Access is
702 * already revoked. This is just an asynchronous
703 * notification so we can put the device asleep (in case
704 * we didn't already notice the access revocation).
705 * "gone": This is like "force" but is sent if the device was
706 * paused due to a device-removal event.
708 * We always handle PauseDevice signals as "force" as we properly
709 * support asynchronous access revocation, anyway. But in case logind
710 * sent mode "pause", we also call PauseDeviceComplete() to immediately
711 * acknowledge the request.
714 r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
716 log_debug("idev-evdev: %s/%s: erroneous PauseDevice signal",
721 /* not our device? */
722 if (makedev(major, minor) != em->devnum)
725 idev_evdev_pause(&em->evdev, true);
727 if (streq(mode, "pause")) {
728 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
731 * Sending PauseDeviceComplete() is racy if logind triggers the
732 * timeout. That is, if we take too long and logind pauses the
733 * device by sending a forced PauseDevice, our
734 * PauseDeviceComplete call will be stray. That's fine, though.
735 * logind ignores such stray calls. Only if logind also sent a
736 * further PauseDevice() signal, it might match our call
737 * incorrectly to the newer PauseDevice(). That's fine, too, as
738 * we handle that event asynchronously, anyway. Therefore,
739 * whatever happens, we're fine. Yay!
742 r = sd_bus_message_new_method_call(c->sysbus,
744 "org.freedesktop.login1",
746 "org.freedesktop.login1.Session",
747 "PauseDeviceComplete");
749 r = sd_bus_message_append(m, "uu", major, minor);
751 r = sd_bus_send(c->sysbus, m, NULL);
755 log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s",
756 s->name, e->name, strerror(-r));
762 static int managed_evdev_resume_device_fn(sd_bus *bus,
763 sd_bus_message *signal,
765 sd_bus_error *ret_error) {
766 managed_evdev *em = userdata;
767 idev_element *e = &em->evdev.element;
768 idev_session *s = e->session;
769 uint32_t major, minor;
773 * We get ResumeDevice signals whenever logind resumed a previously
774 * paused device. The arguments contain the major/minor number of the
775 * related device and a new file-descriptor for the freshly opened
777 * If the signal is not about our device, we simply ignore it.
778 * Otherwise, we take the file-descriptor and immediately resume the
782 r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
784 log_debug("idev-evdev: %s/%s: erroneous ResumeDevice signal",
789 /* not our device? */
790 if (makedev(major, minor) != em->devnum)
793 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
795 log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
800 r = idev_evdev_resume(&em->evdev, fd);
802 log_debug("idev-evdev: %s/%s: cannot resume: %s",
803 s->name, e->name, strerror(-r));
808 static int managed_evdev_setup_bus(managed_evdev *em) {
809 idev_element *e = &em->evdev.element;
810 idev_session *s = e->session;
811 idev_context *c = s->context;
812 _cleanup_free_ char *match = NULL;
815 match = strjoin("type='signal',"
816 "sender='org.freedesktop.login1',"
817 "interface='org.freedesktop.login1.Session',"
818 "member='PauseDevice',"
819 "path='", s->path, "'",
824 r = sd_bus_add_match(c->sysbus,
825 &em->slot_pause_device,
827 managed_evdev_pause_device_fn,
833 match = strjoin("type='signal',"
834 "sender='org.freedesktop.login1',"
835 "interface='org.freedesktop.login1.Session',"
836 "member='ResumeDevice',"
837 "path='", s->path, "'",
842 r = sd_bus_add_match(c->sysbus,
843 &em->slot_resume_device,
845 managed_evdev_resume_device_fn,
853 static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
854 _cleanup_(idev_element_freep) idev_element *e = NULL;
855 char name[IDEV_EVDEV_NAME_MAX];
860 assert_return(s, -EINVAL);
861 assert_return(s->context->sysbus, -EINVAL);
862 assert_return(s->managed, -EINVAL);
863 assert_return(s->context->sysbus, -EINVAL);
864 assert_return(ud, -EINVAL);
866 devnum = udev_device_get_devnum(ud);
870 idev_evdev_name(name, devnum);
872 em = new0(managed_evdev, 1);
876 e = &em->evdev.element;
877 em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s);
880 r = managed_evdev_setup_bus(em);
884 r = idev_element_add(e, name);
894 static void managed_evdev_free(idev_element *e) {
895 managed_evdev *em = managed_evdev_from_element(e);
897 em->slot_resume_device = sd_bus_slot_unref(em->slot_resume_device);
898 em->slot_pause_device = sd_bus_slot_unref(em->slot_pause_device);
899 idev_evdev_destroy(&em->evdev);
903 static const idev_element_vtable managed_evdev_vtable = {
904 .free = managed_evdev_free,
905 .enable = managed_evdev_resume,
906 .disable = managed_evdev_pause,
907 .open = managed_evdev_resume,
908 .close = managed_evdev_pause,
912 * Generic Constructor
913 * Instead of relying on the caller to choose between managed and unmanaged
914 * evdev devices, the idev_evdev_new() constructor does that for you (by
915 * looking at s->managed).
918 bool idev_is_evdev(idev_element *e) {
919 return e && (e->vtable == &unmanaged_evdev_vtable ||
920 e->vtable == &managed_evdev_vtable);
923 idev_element *idev_find_evdev(idev_session *s, dev_t devnum) {
924 char name[IDEV_EVDEV_NAME_MAX];
926 assert_return(s, NULL);
927 assert_return(devnum != 0, NULL);
929 idev_evdev_name(name, devnum);
930 return idev_find_element(s, name);
933 int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
934 assert_return(s, -EINVAL);
935 assert_return(ud, -EINVAL);
937 return s->managed ? managed_evdev_new(out, s, ud) : unmanaged_evdev_new(out, s, ud);