diff options
author | Lyude <lyude@redhat.com> | 2016-11-17 10:06:09 -0500 |
---|---|---|
committer | Lyude <lyude@redhat.com> | 2017-01-26 11:21:42 -0500 |
commit | 6adb7b3737297a32bef50ffb270b83fc314cca6b (patch) | |
tree | 71da9f043eabf8a4c1bed2fa18d0b8916e1b5057 /lib/igt_kms.c | |
parent | c2ddb81c460f95e0074c43687e4bb45fe893198f (diff) |
igt_kms: Add helpers for watching for sysfs hotplug events
This adds some basic helpers for connecting to udev and watching for
sysfs hotplug events.
Cc: Tomeu Vizoso <tomeu@tomeuvizoso.net>
Signed-off-by: Lyude <lyude@redhat.com>
Changes since v1:
- Remove unused arg from documentation
Changes since v2:
- Make udev_monitor explicit so that we can use this for detecting FSMs
from the Chamelium in rpc calls
Diffstat (limited to 'lib/igt_kms.c')
-rw-r--r-- | lib/igt_kms.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/igt_kms.c b/lib/igt_kms.c index 77de678e..df90ca72 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -38,6 +38,10 @@ #elif HAVE_SYS_KD_H #include <sys/kd.h> #endif +#ifdef HAVE_UDEV +#include <libudev.h> +#include <poll.h> +#endif #include <errno.h> #include <time.h> @@ -2920,6 +2924,113 @@ void igt_reset_connectors(void) "detect"); } +#ifdef HAVE_UDEV + +/** + * igt_watch_hotplug: + * + * Begin monitoring udev for sysfs hotplug events. + * + * Returns: a udev monitor for detecting hotplugs on + */ +struct udev_monitor *igt_watch_hotplug(void) +{ + struct udev *udev; + struct udev_monitor *mon; + int ret, flags, fd; + + udev = udev_new(); + igt_assert(udev != NULL); + + mon = udev_monitor_new_from_netlink(udev, "udev"); + igt_assert(mon != NULL); + + ret = udev_monitor_filter_add_match_subsystem_devtype(mon, + "drm", + "drm_minor"); + igt_assert_eq(ret, 0); + ret = udev_monitor_filter_update(mon); + igt_assert_eq(ret, 0); + ret = udev_monitor_enable_receiving(mon); + igt_assert_eq(ret, 0); + + /* Set the fd for udev as non blocking */ + fd = udev_monitor_get_fd(mon); + flags = fcntl(fd, F_GETFL, 0); + igt_assert(flags); + + flags |= O_NONBLOCK; + igt_assert_neq(fcntl(fd, F_SETFL, flags), -1); + + return mon; +} + +/** + * igt_hotplug_detected: + * @mon: A udev monitor initialized with #igt_watch_hotplug + * @timeout_secs: How long to wait for a hotplug event to occur. + * + * Assert that a hotplug event was received since we last checked the monitor. + * + * Returns: true if a sysfs hotplug event was received, false if we timed out + */ +bool igt_hotplug_detected(struct udev_monitor *mon, int timeout_secs) +{ + struct udev_device *dev; + const char *hotplug_val; + struct pollfd fd = { + .fd = udev_monitor_get_fd(mon), + .events = POLLIN + }; + bool hotplug_received = false; + + /* Go through all of the events pending on the udev monitor. Once we + * receive a hotplug, we continue going through the rest of the events + * so that redundant hotplug events don't change the results of future + * checks + */ + while (!hotplug_received && poll(&fd, 1, timeout_secs * 1000)) { + dev = udev_monitor_receive_device(mon); + + hotplug_val = udev_device_get_property_value(dev, "HOTPLUG"); + if (hotplug_val && atoi(hotplug_val) == 1) + hotplug_received = true; + + udev_device_unref(dev); + } + + return hotplug_received; +} + +/** + * igt_flush_hotplugs: + * @mon: A udev monitor initialized with #igt_watch_hotplug + * + * Get rid of any pending hotplug events + */ +void igt_flush_hotplugs(struct udev_monitor *mon) +{ + struct udev_device *dev; + + while ((dev = udev_monitor_receive_device(mon))) + udev_device_unref(dev); +} + +/** + * igt_cleanup_hotplug: + * + * Cleanup the resources allocated by #igt_watch_hotplug + */ +void igt_cleanup_hotplug(struct udev_monitor *mon) +{ + struct udev *udev = udev_monitor_get_udev(mon); + + udev_monitor_unref(mon); + mon = NULL; + udev_unref(udev); +} +#endif + /** * kmstest_get_vbl_flag: * @pipe_id: Pipe to convert to flag representation. |