From c86ad7b19e4e10509eef3df7f9f4d656258017d5 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 22:20:56 +0300 Subject: [PATCH 01/13] backend/libinput/tablet_pad.c: explicitly include libudev --- backend/libinput/tablet_pad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index 083711ef0..8b9daef72 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "backend/libinput.h" From 81d935e03549b91ea0d0f5e15c81baf3c3d6ccb3 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 22:21:06 +0300 Subject: [PATCH 02/13] backend/libinput/tablet_tool.c: explicitly include libudev --- backend/libinput/tablet_tool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 31cd18b8c..04f11d8fa 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "backend/libinput.h" From 121b9ca8afa79225c5d36bfa4ed58631ed6745fe Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 21:34:41 +0300 Subject: [PATCH 03/13] include/backend/session/dev.h: prepare prototypes --- include/backend/session/dev.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 include/backend/session/dev.h diff --git a/include/backend/session/dev.h b/include/backend/session/dev.h new file mode 100644 index 000000000..56aae36e1 --- /dev/null +++ b/include/backend/session/dev.h @@ -0,0 +1,13 @@ +#include +#include +#include + +#ifndef BACKEND_SESSION_DEV_H +#define BACKEND_SESSION_DEV_H + +int dev_init(struct wlr_session *session, struct wl_display *display); +void dev_finish(struct wlr_session *session); + +ssize_t dev_find_gpus(struct wlr_session *session, size_t ret_len, + struct wlr_device **ret); +#endif From 968e1277bc8cb8051254c37209dc6f8ddedb98c4 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 21:35:38 +0300 Subject: [PATCH 04/13] backend/session/session.c: decouple udev to backend/session/dev_udev.c --- backend/session/dev_udev.c | 308 ++++++++++++++++++++++++++++++++++++ backend/session/meson.build | 2 +- backend/session/session.c | 279 +------------------------------- 3 files changed, 314 insertions(+), 275 deletions(-) create mode 100644 backend/session/dev_udev.c diff --git a/backend/session/dev_udev.c b/backend/session/dev_udev.c new file mode 100644 index 000000000..88dab7b33 --- /dev/null +++ b/backend/session/dev_udev.c @@ -0,0 +1,308 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" +#include "backend/session/dev.h" +#include "util/signal.h" + +#define WAIT_GPU_TIMEOUT 10000 // ms + +static bool is_drm_card(const char *sysname) { + const char prefix[] = DRM_PRIMARY_MINOR_NAME; + if (strncmp(sysname, prefix, strlen(prefix)) != 0) { + return false; + } + for (size_t i = strlen(prefix); sysname[i] != '\0'; i++) { + if (sysname[i] < '0' || sysname[i] > '9') { + return false; + } + } + return true; +} + +static void read_udev_change_event(struct wlr_device_change_event *event, + struct udev_device *udev_dev) { + const char *hotplug = udev_device_get_property_value(udev_dev, "HOTPLUG"); + if (hotplug != NULL && strcmp(hotplug, "1") == 0) { + event->type = WLR_DEVICE_HOTPLUG; + struct wlr_device_hotplug_event *hotplug = &event->hotplug; + + const char *connector = + udev_device_get_property_value(udev_dev, "CONNECTOR"); + if (connector != NULL) { + hotplug->connector_id = strtoul(connector, NULL, 10); + } + + const char *prop = + udev_device_get_property_value(udev_dev, "PROPERTY"); + if (prop != NULL) { + hotplug->prop_id = strtoul(prop, NULL, 10); + } + + return; + } + + const char *lease = udev_device_get_property_value(udev_dev, "LEASE"); + if (lease != NULL && strcmp(lease, "1") == 0) { + event->type = WLR_DEVICE_LEASE; + return; + } +} + +static int handle_udev_event(int fd, uint32_t mask, void *data) { + struct wlr_session *session = data; + + struct udev_device *udev_dev = udev_monitor_receive_device(session->mon); + if (!udev_dev) { + return 1; + } + + const char *sysname = udev_device_get_sysname(udev_dev); + const char *devnode = udev_device_get_devnode(udev_dev); + const char *action = udev_device_get_action(udev_dev); + wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action); + + if (!is_drm_card(sysname) || !action || !devnode) { + goto out; + } + + const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT"); + if (!seat) { + seat = "seat0"; + } + if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { + goto out; + } + + if (strcmp(action, "add") == 0) { + wlr_log(WLR_DEBUG, "DRM device %s added", sysname); + struct wlr_session_add_event event = { + .path = devnode, + }; + wlr_signal_emit_safe(&session->events.add_drm_card, &event); + } else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) { + dev_t devnum = udev_device_get_devnum(udev_dev); + struct wlr_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->dev != devnum) { + continue; + } + + if (strcmp(action, "change") == 0) { + wlr_log(WLR_DEBUG, "DRM device %s changed", sysname); + struct wlr_device_change_event event = {0}; + read_udev_change_event(&event, udev_dev); + wlr_signal_emit_safe(&dev->events.change, &event); + } else if (strcmp(action, "remove") == 0) { + wlr_log(WLR_DEBUG, "DRM device %s removed", sysname); + wlr_signal_emit_safe(&dev->events.remove, NULL); + } else { + assert(0); + } + break; + } + } + +out: + udev_device_unref(udev_dev); + return 1; +} + +int dev_init(struct wlr_session *session, struct wl_display *disp) { + session->udev = udev_new(); + if (!session->udev) { + wlr_log_errno(WLR_ERROR, "Failed to create udev context"); + return -1; + } + + session->mon = udev_monitor_new_from_netlink(session->udev, "udev"); + if (!session->mon) { + wlr_log_errno(WLR_ERROR, "Failed to create udev monitor"); + goto error_udev; + } + + udev_monitor_filter_add_match_subsystem_devtype(session->mon, "drm", NULL); + udev_monitor_enable_receiving(session->mon); + + struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); + int fd = udev_monitor_get_fd(session->mon); + + session->udev_event = wl_event_loop_add_fd(event_loop, fd, + WL_EVENT_READABLE, handle_udev_event, session); + if (!session->udev_event) { + wlr_log_errno(WLR_ERROR, "Failed to create udev event source"); + goto error_mon; + } + + return 0; + +error_mon: + udev_monitor_unref(session->mon); +error_udev: + udev_unref(session->udev); + return -1; +} + +void dev_finish(struct wlr_session *session) { + if (!session) { + return; + } + + wl_event_source_remove(session->udev_event); + udev_monitor_unref(session->mon); + udev_unref(session->udev); +} + +static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { + struct udev_enumerate *en = udev_enumerate_new(udev); + if (!en) { + wlr_log(WLR_ERROR, "udev_enumerate_new failed"); + return NULL; + } + + udev_enumerate_add_match_subsystem(en, "drm"); + udev_enumerate_add_match_sysname(en, DRM_PRIMARY_MINOR_NAME "[0-9]*"); + + if (udev_enumerate_scan_devices(en) != 0) { + wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed"); + udev_enumerate_unref(en); + return NULL; + } + + return en; +} + +static uint64_t get_current_time_ms(void) { + struct timespec ts = {0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} + +struct find_gpus_add_handler { + bool added; + struct wl_listener listener; +}; + +static void find_gpus_handle_add(struct wl_listener *listener, void *data) { + struct find_gpus_add_handler *handler = + wl_container_of(listener, handler, listener); + handler->added = true; +} + +/* Tries to find the primary GPU by checking for the "boot_vga" attribute. + * If it's not found, it returns the first valid GPU it finds. + */ +ssize_t dev_find_gpus(struct wlr_session *session, + size_t ret_len, struct wlr_device **ret) { + struct udev_enumerate *en = enumerate_drm_cards(session->udev); + if (!en) { + return -1; + } + + if (udev_enumerate_get_list_entry(en) == NULL) { + udev_enumerate_unref(en); + wlr_log(WLR_INFO, "Waiting for a DRM card device"); + + struct find_gpus_add_handler handler = {0}; + handler.listener.notify = find_gpus_handle_add; + wl_signal_add(&session->events.add_drm_card, &handler.listener); + + uint64_t started_at = get_current_time_ms(); + uint64_t timeout = WAIT_GPU_TIMEOUT; + struct wl_event_loop *event_loop = + wl_display_get_event_loop(session->display); + while (!handler.added) { + int ret = wl_event_loop_dispatch(event_loop, (int)timeout); + if (ret < 0) { + wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: " + "wl_event_loop_dispatch failed"); + udev_enumerate_unref(en); + return -1; + } + + uint64_t now = get_current_time_ms(); + if (now >= started_at + WAIT_GPU_TIMEOUT) { + break; + } + timeout = started_at + WAIT_GPU_TIMEOUT - now; + } + + wl_list_remove(&handler.listener.link); + + en = enumerate_drm_cards(session->udev); + if (!en) { + return -1; + } + } + + struct udev_list_entry *entry; + size_t i = 0; + + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { + if (i == ret_len) { + break; + } + + bool is_boot_vga = false; + + const char *path = udev_list_entry_get_name(entry); + struct udev_device *dev = udev_device_new_from_syspath(session->udev, path); + if (!dev) { + continue; + } + + const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); + if (!seat) { + seat = "seat0"; + } + if (session->seat[0] && strcmp(session->seat, seat) != 0) { + udev_device_unref(dev); + continue; + } + + // This is owned by 'dev', so we don't need to free it + struct udev_device *pci = + udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL); + + if (pci) { + const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); + if (id && strcmp(id, "1") == 0) { + is_boot_vga = true; + } + } + + struct wlr_device *wlr_dev = + session_open_if_kms(session, udev_device_get_devnode(dev)); + if (!wlr_dev) { + udev_device_unref(dev); + continue; + } + + udev_device_unref(dev); + + ret[i] = wlr_dev; + if (is_boot_vga) { + struct wlr_device *tmp = ret[0]; + ret[0] = ret[i]; + ret[i] = tmp; + } + + ++i; + } + + udev_enumerate_unref(en); + + return i; +} diff --git a/backend/session/meson.build b/backend/session/meson.build index 27915506b..f0ff132f1 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -3,5 +3,5 @@ libseat = dependency('libseat', fallback: 'seatd', default_options: ['server=disabled', 'man-pages=disabled'], ) -wlr_files += files('session.c') +wlr_files += files('session.c', 'dev_udev.c') wlr_deps += libseat diff --git a/backend/session/session.c b/backend/session/session.c index 7d6d080da..cd46a04fb 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -1,8 +1,5 @@ #define _POSIX_C_SOURCE 200809L -#include -#include #include -#include #include #include #include @@ -14,15 +11,13 @@ #include #include #include -#include #include #include "backend/session/session.h" +#include "backend/session/dev.h" #include "util/signal.h" #include -#define WAIT_GPU_TIMEOUT 10000 // ms - static void handle_enable_seat(struct libseat *seat, void *data) { struct wlr_session *session = data; session->active = true; @@ -126,107 +121,6 @@ static void libseat_session_finish(struct wlr_session *session) { session->libseat_event = NULL; } -static bool is_drm_card(const char *sysname) { - const char prefix[] = DRM_PRIMARY_MINOR_NAME; - if (strncmp(sysname, prefix, strlen(prefix)) != 0) { - return false; - } - for (size_t i = strlen(prefix); sysname[i] != '\0'; i++) { - if (sysname[i] < '0' || sysname[i] > '9') { - return false; - } - } - return true; -} - -static void read_udev_change_event(struct wlr_device_change_event *event, - struct udev_device *udev_dev) { - const char *hotplug = udev_device_get_property_value(udev_dev, "HOTPLUG"); - if (hotplug != NULL && strcmp(hotplug, "1") == 0) { - event->type = WLR_DEVICE_HOTPLUG; - struct wlr_device_hotplug_event *hotplug = &event->hotplug; - - const char *connector = - udev_device_get_property_value(udev_dev, "CONNECTOR"); - if (connector != NULL) { - hotplug->connector_id = strtoul(connector, NULL, 10); - } - - const char *prop = - udev_device_get_property_value(udev_dev, "PROPERTY"); - if (prop != NULL) { - hotplug->prop_id = strtoul(prop, NULL, 10); - } - - return; - } - - const char *lease = udev_device_get_property_value(udev_dev, "LEASE"); - if (lease != NULL && strcmp(lease, "1") == 0) { - event->type = WLR_DEVICE_LEASE; - return; - } -} - -static int handle_udev_event(int fd, uint32_t mask, void *data) { - struct wlr_session *session = data; - - struct udev_device *udev_dev = udev_monitor_receive_device(session->mon); - if (!udev_dev) { - return 1; - } - - const char *sysname = udev_device_get_sysname(udev_dev); - const char *devnode = udev_device_get_devnode(udev_dev); - const char *action = udev_device_get_action(udev_dev); - wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action); - - if (!is_drm_card(sysname) || !action || !devnode) { - goto out; - } - - const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT"); - if (!seat) { - seat = "seat0"; - } - if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { - goto out; - } - - if (strcmp(action, "add") == 0) { - wlr_log(WLR_DEBUG, "DRM device %s added", sysname); - struct wlr_session_add_event event = { - .path = devnode, - }; - wlr_signal_emit_safe(&session->events.add_drm_card, &event); - } else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) { - dev_t devnum = udev_device_get_devnum(udev_dev); - struct wlr_device *dev; - wl_list_for_each(dev, &session->devices, link) { - if (dev->dev != devnum) { - continue; - } - - if (strcmp(action, "change") == 0) { - wlr_log(WLR_DEBUG, "DRM device %s changed", sysname); - struct wlr_device_change_event event = {0}; - read_udev_change_event(&event, udev_dev); - wlr_signal_emit_safe(&dev->events.change, &event); - } else if (strcmp(action, "remove") == 0) { - wlr_log(WLR_DEBUG, "DRM device %s removed", sysname); - wlr_signal_emit_safe(&dev->events.remove, NULL); - } else { - assert(0); - } - break; - } - } - -out: - udev_device_unref(udev_dev); - return 1; -} - static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_session *session = wl_container_of(listener, session, display_destroy); @@ -250,31 +144,11 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { goto error_open; } - session->udev = udev_new(); - if (!session->udev) { - wlr_log_errno(WLR_ERROR, "Failed to create udev context"); + if (dev_init(session, disp) == -1) { + wlr_log(WLR_ERROR, "Failed to initialize dev backend"); goto error_session; } - session->mon = udev_monitor_new_from_netlink(session->udev, "udev"); - if (!session->mon) { - wlr_log_errno(WLR_ERROR, "Failed to create udev monitor"); - goto error_udev; - } - - udev_monitor_filter_add_match_subsystem_devtype(session->mon, "drm", NULL); - udev_monitor_enable_receiving(session->mon); - - struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); - int fd = udev_monitor_get_fd(session->mon); - - session->udev_event = wl_event_loop_add_fd(event_loop, fd, - WL_EVENT_READABLE, handle_udev_event, session); - if (!session->udev_event) { - wlr_log_errno(WLR_ERROR, "Failed to create udev event source"); - goto error_mon; - } - session->display = disp; session->display_destroy.notify = handle_display_destroy; @@ -282,10 +156,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return session; -error_mon: - udev_monitor_unref(session->mon); -error_udev: - udev_unref(session->udev); error_session: libseat_session_finish(session); error_open: @@ -301,9 +171,7 @@ void wlr_session_destroy(struct wlr_session *session) { wlr_signal_emit_safe(&session->events.destroy, session); wl_list_remove(&session->display_destroy.link); - wl_event_source_remove(session->udev_event); - udev_monitor_unref(session->mon); - udev_unref(session->udev); + dev_finish(session); struct wlr_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, &session->devices, link) { @@ -418,45 +286,6 @@ static ssize_t explicit_find_gpus(struct wlr_session *session, return i; } -static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { - struct udev_enumerate *en = udev_enumerate_new(udev); - if (!en) { - wlr_log(WLR_ERROR, "udev_enumerate_new failed"); - return NULL; - } - - udev_enumerate_add_match_subsystem(en, "drm"); - udev_enumerate_add_match_sysname(en, DRM_PRIMARY_MINOR_NAME "[0-9]*"); - - if (udev_enumerate_scan_devices(en) != 0) { - wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed"); - udev_enumerate_unref(en); - return NULL; - } - - return en; -} - -static uint64_t get_current_time_ms(void) { - struct timespec ts = {0}; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; -} - -struct find_gpus_add_handler { - bool added; - struct wl_listener listener; -}; - -static void find_gpus_handle_add(struct wl_listener *listener, void *data) { - struct find_gpus_add_handler *handler = - wl_container_of(listener, handler, listener); - handler->added = true; -} - -/* Tries to find the primary GPU by checking for the "boot_vga" attribute. - * If it's not found, it returns the first valid GPU it finds. - */ ssize_t wlr_session_find_gpus(struct wlr_session *session, size_t ret_len, struct wlr_device **ret) { const char *explicit = getenv("WLR_DRM_DEVICES"); @@ -464,103 +293,5 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, return explicit_find_gpus(session, ret_len, ret, explicit); } - struct udev_enumerate *en = enumerate_drm_cards(session->udev); - if (!en) { - return -1; - } - - if (udev_enumerate_get_list_entry(en) == NULL) { - udev_enumerate_unref(en); - wlr_log(WLR_INFO, "Waiting for a DRM card device"); - - struct find_gpus_add_handler handler = {0}; - handler.listener.notify = find_gpus_handle_add; - wl_signal_add(&session->events.add_drm_card, &handler.listener); - - uint64_t started_at = get_current_time_ms(); - uint64_t timeout = WAIT_GPU_TIMEOUT; - struct wl_event_loop *event_loop = - wl_display_get_event_loop(session->display); - while (!handler.added) { - int ret = wl_event_loop_dispatch(event_loop, (int)timeout); - if (ret < 0) { - wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: " - "wl_event_loop_dispatch failed"); - udev_enumerate_unref(en); - return -1; - } - - uint64_t now = get_current_time_ms(); - if (now >= started_at + WAIT_GPU_TIMEOUT) { - break; - } - timeout = started_at + WAIT_GPU_TIMEOUT - now; - } - - wl_list_remove(&handler.listener.link); - - en = enumerate_drm_cards(session->udev); - if (!en) { - return -1; - } - } - - struct udev_list_entry *entry; - size_t i = 0; - - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { - if (i == ret_len) { - break; - } - - bool is_boot_vga = false; - - const char *path = udev_list_entry_get_name(entry); - struct udev_device *dev = udev_device_new_from_syspath(session->udev, path); - if (!dev) { - continue; - } - - const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); - if (!seat) { - seat = "seat0"; - } - if (session->seat[0] && strcmp(session->seat, seat) != 0) { - udev_device_unref(dev); - continue; - } - - // This is owned by 'dev', so we don't need to free it - struct udev_device *pci = - udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL); - - if (pci) { - const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); - if (id && strcmp(id, "1") == 0) { - is_boot_vga = true; - } - } - - struct wlr_device *wlr_dev = - session_open_if_kms(session, udev_device_get_devnode(dev)); - if (!wlr_dev) { - udev_device_unref(dev); - continue; - } - - udev_device_unref(dev); - - ret[i] = wlr_dev; - if (is_boot_vga) { - struct wlr_device *tmp = ret[0]; - ret[0] = ret[i]; - ret[i] = tmp; - } - - ++i; - } - - udev_enumerate_unref(en); - - return i; + return dev_find_gpus(session, ret_len, ret); } From e706875432751244794933f447cc4c016c7d9cad Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 21:51:22 +0300 Subject: [PATCH 05/13] include/backend/session/dev_udev.h: prepare declarations --- include/backend/session/dev_udev.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 include/backend/session/dev_udev.h diff --git a/include/backend/session/dev_udev.h b/include/backend/session/dev_udev.h new file mode 100644 index 000000000..186984494 --- /dev/null +++ b/include/backend/session/dev_udev.h @@ -0,0 +1,13 @@ +#include +#include + +#ifndef BACKEND_SESSION_DEV_UDEV_H +#define BACKEND_SESSION_DEV_UDEV_H + +struct dev { + struct udev *udev; + struct udev_monitor *mon; + struct wl_event_source *udev_event; +}; + +#endif From 68652158b79af55637c36b74aabf9fe3256a0905 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 22:13:27 +0300 Subject: [PATCH 06/13] backend/session/dev_udev.c, backend/libinput/backend.c: decouple udev from include/wlr/backend/session/session.h --- backend/libinput/backend.c | 3 ++- backend/session/dev_udev.c | 49 +++++++++++++++++++++-------------- include/wlr/backend/session.h | 6 ++--- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 60f456cc1..5eac2c96b 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -6,6 +6,7 @@ #include #include #include "backend/libinput.h" +#include "backend/session/dev_udev.h" #include "util/signal.h" static struct wlr_libinput_backend *get_libinput_backend_from_backend( @@ -87,7 +88,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) { wlr_log(WLR_DEBUG, "Starting libinput backend"); backend->libinput_context = libinput_udev_create_context(&libinput_impl, - backend, backend->session->udev); + backend, backend->session->dev->udev); if (!backend->libinput_context) { wlr_log(WLR_ERROR, "Failed to create libinput context"); return false; diff --git a/backend/session/dev_udev.c b/backend/session/dev_udev.c index 88dab7b33..338e43b57 100644 --- a/backend/session/dev_udev.c +++ b/backend/session/dev_udev.c @@ -15,6 +15,7 @@ #include #include "backend/session/session.h" #include "backend/session/dev.h" +#include "backend/session/dev_udev.h" #include "util/signal.h" #define WAIT_GPU_TIMEOUT 10000 // ms @@ -64,7 +65,7 @@ static void read_udev_change_event(struct wlr_device_change_event *event, static int handle_udev_event(int fd, uint32_t mask, void *data) { struct wlr_session *session = data; - struct udev_device *udev_dev = udev_monitor_receive_device(session->mon); + struct udev_device *udev_dev = udev_monitor_receive_device(session->dev->mon); if (!udev_dev) { return 1; } @@ -121,37 +122,46 @@ out: } int dev_init(struct wlr_session *session, struct wl_display *disp) { - session->udev = udev_new(); - if (!session->udev) { - wlr_log_errno(WLR_ERROR, "Failed to create udev context"); + struct dev *dev = calloc(1, sizeof(*dev)); + if (!dev) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); return -1; } - session->mon = udev_monitor_new_from_netlink(session->udev, "udev"); - if (!session->mon) { + dev->udev = udev_new(); + if (!dev->udev) { + wlr_log_errno(WLR_ERROR, "Failed to create udev context"); + goto error_dev; + } + + dev->mon = udev_monitor_new_from_netlink(dev->udev, "udev"); + if (!dev->mon) { wlr_log_errno(WLR_ERROR, "Failed to create udev monitor"); goto error_udev; } - udev_monitor_filter_add_match_subsystem_devtype(session->mon, "drm", NULL); - udev_monitor_enable_receiving(session->mon); + udev_monitor_filter_add_match_subsystem_devtype(dev->mon, "drm", NULL); + udev_monitor_enable_receiving(dev->mon); struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); - int fd = udev_monitor_get_fd(session->mon); + int fd = udev_monitor_get_fd(dev->mon); - session->udev_event = wl_event_loop_add_fd(event_loop, fd, + dev->udev_event = wl_event_loop_add_fd(event_loop, fd, WL_EVENT_READABLE, handle_udev_event, session); - if (!session->udev_event) { + if (!dev->udev_event) { wlr_log_errno(WLR_ERROR, "Failed to create udev event source"); goto error_mon; } + session->dev = dev; return 0; error_mon: - udev_monitor_unref(session->mon); + udev_monitor_unref(dev->mon); error_udev: - udev_unref(session->udev); + udev_unref(dev->udev); +error_dev: + free(dev); return -1; } @@ -160,9 +170,10 @@ void dev_finish(struct wlr_session *session) { return; } - wl_event_source_remove(session->udev_event); - udev_monitor_unref(session->mon); - udev_unref(session->udev); + wl_event_source_remove(session->dev->udev_event); + udev_monitor_unref(session->dev->mon); + udev_unref(session->dev->udev); + free(session->dev); } static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { @@ -206,7 +217,7 @@ static void find_gpus_handle_add(struct wl_listener *listener, void *data) { */ ssize_t dev_find_gpus(struct wlr_session *session, size_t ret_len, struct wlr_device **ret) { - struct udev_enumerate *en = enumerate_drm_cards(session->udev); + struct udev_enumerate *en = enumerate_drm_cards(session->dev->udev); if (!en) { return -1; } @@ -241,7 +252,7 @@ ssize_t dev_find_gpus(struct wlr_session *session, wl_list_remove(&handler.listener.link); - en = enumerate_drm_cards(session->udev); + en = enumerate_drm_cards(session->dev->udev); if (!en) { return -1; } @@ -258,7 +269,7 @@ ssize_t dev_find_gpus(struct wlr_session *session, bool is_boot_vga = false; const char *path = udev_list_entry_get_name(entry); - struct udev_device *dev = udev_device_new_from_syspath(session->udev, path); + struct udev_device *dev = udev_device_new_from_syspath(session->dev->udev, path); if (!dev) { continue; } diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index c8461ff7c..0f2e09722 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -1,12 +1,12 @@ #ifndef WLR_BACKEND_SESSION_H #define WLR_BACKEND_SESSION_H -#include #include #include #include struct libseat; +struct dev; struct wlr_device { int fd; @@ -34,9 +34,7 @@ struct wlr_session { unsigned vtnr; char seat[256]; - struct udev *udev; - struct udev_monitor *mon; - struct wl_event_source *udev_event; + struct dev *dev; struct libseat *seat_handle; struct wl_event_source *libseat_event; From 3468395cba5abcf54b2beb054241b254f610928d Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 22:45:09 +0300 Subject: [PATCH 07/13] backend/libinput/backend.c, backend/libinput/tablet_pad.c, backend/libinput/tablet_tool.c, backend/session/session.c: make udev optional --- backend/libinput/backend.c | 22 +++++++++++++++++++++- backend/libinput/tablet_pad.c | 8 +++++++- backend/libinput/tablet_tool.c | 8 +++++++- backend/session/meson.build | 17 ++++++++++++++++- backend/session/session.c | 10 ++++++++++ include/wlr/config.h.in | 2 ++ meson.build | 3 +-- meson_options.txt | 1 + 8 files changed, 65 insertions(+), 6 deletions(-) diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 5eac2c96b..2dcbc5024 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -5,10 +5,16 @@ #include #include #include +#include #include "backend/libinput.h" -#include "backend/session/dev_udev.h" #include "util/signal.h" +#if WLR_HAS_UDEV +#include "backend/session/dev_udev.h" +#endif + +#define NETLINK_BITMASK 4 + static struct wlr_libinput_backend *get_libinput_backend_from_backend( struct wlr_backend *wlr_backend) { assert(wlr_backend_is_libinput(wlr_backend)); @@ -87,15 +93,29 @@ static bool backend_start(struct wlr_backend *wlr_backend) { get_libinput_backend_from_backend(wlr_backend); wlr_log(WLR_DEBUG, "Starting libinput backend"); +#if WLR_HAS_UDEV backend->libinput_context = libinput_udev_create_context(&libinput_impl, backend, backend->session->dev->udev); +#elif defined(__linux__) + backend->libinput_context = libinput_netlink_create_context(&libinput_impl, + backend, NETLINK_BITMASK); +#else +#error Unsupported platform +#endif if (!backend->libinput_context) { wlr_log(WLR_ERROR, "Failed to create libinput context"); return false; } +#if WLR_HAS_UDEV if (libinput_udev_assign_seat(backend->libinput_context, backend->session->seat) != 0) { +#elif defined(__linux__) + if (libinput_netlink_assign_seat(backend->libinput_context, + backend->session->seat) != 0) { +#else +#error Unsupported platform +#endif wlr_log(WLR_ERROR, "Failed to assign libinput seat"); return false; } diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c index 8b9daef72..580676ec4 100644 --- a/backend/libinput/tablet_pad.c +++ b/backend/libinput/tablet_pad.c @@ -3,12 +3,16 @@ #include #include #include -#include #include #include +#include #include "backend/libinput.h" #include "util/signal.h" +#if WLR_HAS_UDEV +#include +#endif + const struct wlr_tablet_pad_impl libinput_tablet_pad_impl = { .name = "libinput-tablet-pad", }; @@ -107,9 +111,11 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) { wlr_tablet_pad->strip_count = libinput_device_tablet_pad_get_num_strips(handle); +#if WLR_HAS_UDEV struct udev_device *udev = libinput_device_get_udev_device(handle); char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *)); *dst = strdup(udev_device_get_syspath(udev)); +#endif int groups = libinput_device_tablet_pad_get_num_mode_groups(handle); for (int i = 0; i < groups; ++i) { diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 04f11d8fa..5d0f6edba 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -3,12 +3,16 @@ #include #include #include -#include #include #include +#include #include "backend/libinput.h" #include "util/signal.h" +#if WLR_HAS_UDEV +#include +#endif + struct tablet_tool { struct wlr_tablet_tool wlr_tool; struct libinput_tablet_tool *handle; @@ -29,9 +33,11 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) { libinput_device_get_size(dev->handle, &wlr_tablet->width_mm, &wlr_tablet->height_mm); +#if WLR_HAS_UDEV struct udev_device *udev = libinput_device_get_udev_device(dev->handle); char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *)); *dst = strdup(udev_device_get_syspath(udev)); +#endif wl_list_init(&dev->tablet_tools); } diff --git a/backend/session/meson.build b/backend/session/meson.build index f0ff132f1..f407a2131 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -3,5 +3,20 @@ libseat = dependency('libseat', fallback: 'seatd', default_options: ['server=disabled', 'man-pages=disabled'], ) -wlr_files += files('session.c', 'dev_udev.c') +wlr_files += files('session.c') wlr_deps += libseat + +# libudev + +if get_option('enum-backend') == 'auto' + udev = dependency('libudev', required: false) + if udev.found() + wlr_files += files('dev_udev.c') + wlr_deps += udev + features += { 'udev': true } + endif +elif get_option('enum-backend') == 'udev' + wlr_files += files('dev_udev.c') + wlr_deps += dependency('libudev') + features += { 'udev': true } +endif diff --git a/backend/session/session.c b/backend/session/session.c index cd46a04fb..2d18d4231 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -144,10 +144,12 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { goto error_open; } +#if WLR_HAS_UDEV if (dev_init(session, disp) == -1) { wlr_log(WLR_ERROR, "Failed to initialize dev backend"); goto error_session; } +#endif session->display = disp; @@ -156,8 +158,10 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return session; +#if WLR_HAS_UDEV error_session: libseat_session_finish(session); +#endif error_open: free(session); return NULL; @@ -171,7 +175,9 @@ void wlr_session_destroy(struct wlr_session *session) { wlr_signal_emit_safe(&session->events.destroy, session); wl_list_remove(&session->display_destroy.link); +#if WLR_HAS_UDEV dev_finish(session); +#endif struct wlr_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, &session->devices, link) { @@ -293,5 +299,9 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, return explicit_find_gpus(session, ret_len, ret, explicit); } +#if WLR_HAS_UDEV return dev_find_gpus(session, ret_len, ret); +#endif + + return -1; } diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index 71868a349..e636bf5e0 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -11,4 +11,6 @@ #mesondefine WLR_HAS_XWAYLAND +#mesondefine WLR_HAS_UDEV + #endif diff --git a/meson.build b/meson.build index f7fb659c4..ec3b734db 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ features = { 'xwayland': false, 'gles2-renderer': false, 'vulkan-renderer': false, + 'udev': false, } internal_features = { 'xcb-errors': false, @@ -127,7 +128,6 @@ drm = dependency('libdrm', ) gbm = dependency('gbm', version: '>=17.1.0') xkbcommon = dependency('xkbcommon') -udev = dependency('libudev') pixman = dependency('pixman-1') math = cc.find_library('m') rt = cc.find_library('rt') @@ -138,7 +138,6 @@ wlr_deps = [ drm, gbm, xkbcommon, - udev, pixman, math, rt, diff --git a/meson_options.txt b/meson_options.txt index 550acbe6f..01eca736e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,3 +4,4 @@ option('examples', type: 'boolean', value: true, description: 'Build example app option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') +option('enum-backend', type: 'combo', choices: ['auto', 'disabled', 'udev'], value: 'udev', description: 'Select device enumeration backend') From 272e8488af92a153cfca022f9cc26175c7049486 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 23:00:28 +0300 Subject: [PATCH 08/13] backend/session/session.c: enumerate gpus using drmGetDevices2 --- backend/session/session.c | 55 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/backend/session/session.c b/backend/session/session.c index 2d18d4231..f2917fcad 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "backend/session/session.h" #include "backend/session/dev.h" @@ -303,5 +304,57 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, return dev_find_gpus(session, ret_len, ret); #endif - return -1; + int cnt = drmGetDevices2(0, NULL, 0); + if (cnt <= 0) { + return cnt == 0 ? 0 : -1; + } + + drmDevicePtr *devs = calloc(cnt, sizeof(*devs)); + if (!devs) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + + cnt = drmGetDevices2(0, devs, cnt); + if (cnt <= 0) { + free(devs); + return cnt == 0 ? 0 : -1; + } + + ssize_t total = 0; + size_t max = (size_t)cnt > ret_len ? ret_len : (size_t)cnt; + + for (size_t i = 0; i < max; i++) { + if (!(devs[i]->available_nodes & (1 << DRM_NODE_PRIMARY))) { + continue; + } + + // TODO + bool is_boot_vga = false; + + // TODO https://todo.sr.ht/~kennylevinsen/seatd/1 + const char *seat = "seat0"; + if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { + continue; + } + + const char *devnode = devs[i]->nodes[DRM_NODE_PRIMARY]; + struct wlr_device *wlr_dev = session_open_if_kms(session, devnode); + if (!wlr_dev) { + continue; + } + + ret[total] = wlr_dev; + if (is_boot_vga) { + struct wlr_device *tmp = ret[0]; + ret[0] = ret[total]; + ret[total] = tmp; + } + + total++; + } + + drmFreeDevices(devs, cnt); + free(devs); + return total; } From 5161682b1b8b359b490c285c41bcbc8dc8d81f27 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 23:33:53 +0300 Subject: [PATCH 09/13] include/backend/session/dev_demi.h: prepare declarations --- include/backend/session/dev_demi.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 include/backend/session/dev_demi.h diff --git a/include/backend/session/dev_demi.h b/include/backend/session/dev_demi.h new file mode 100644 index 000000000..b2a113fa6 --- /dev/null +++ b/include/backend/session/dev_demi.h @@ -0,0 +1,11 @@ +#include + +#ifndef BACKEND_SESSION_DEV_DEMI_H +#define BACKEND_SESSION_DEV_DEMI_H + +struct dev { + int fd; + struct wl_event_source *event; +}; + +#endif From ab2425e65f587db0e12bce36f58fb2f81a169bf2 Mon Sep 17 00:00:00 2001 From: illiliti Date: Sun, 13 Mar 2022 23:50:39 +0300 Subject: [PATCH 10/13] backend/libinput/backend.c, backend/session/session.c: implement libdemi support --- backend/libinput/backend.c | 4 + backend/session/dev_demi.c | 148 ++++++++++++++++++++++++++++++++++++ backend/session/meson.build | 11 ++- backend/session/session.c | 6 +- include/wlr/config.h.in | 1 + meson.build | 1 + meson_options.txt | 2 +- 7 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 backend/session/dev_demi.c diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 2dcbc5024..21fdfe361 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -96,6 +96,8 @@ static bool backend_start(struct wlr_backend *wlr_backend) { #if WLR_HAS_UDEV backend->libinput_context = libinput_udev_create_context(&libinput_impl, backend, backend->session->dev->udev); +#elif WLR_HAS_DEMI + backend->libinput_context = libinput_create_context(&libinput_impl, backend); #elif defined(__linux__) backend->libinput_context = libinput_netlink_create_context(&libinput_impl, backend, NETLINK_BITMASK); @@ -110,6 +112,8 @@ static bool backend_start(struct wlr_backend *wlr_backend) { #if WLR_HAS_UDEV if (libinput_udev_assign_seat(backend->libinput_context, backend->session->seat) != 0) { +#elif WLR_HAS_DEMI + if (libinput_assign_seat(backend->libinput_context, backend->session->seat) != 0) { #elif defined(__linux__) if (libinput_netlink_assign_seat(backend->libinput_context, backend->session->seat) != 0) { diff --git a/backend/session/dev_demi.c b/backend/session/dev_demi.c new file mode 100644 index 000000000..a10b0243d --- /dev/null +++ b/backend/session/dev_demi.c @@ -0,0 +1,148 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" +#include "backend/session/dev.h" +#include "backend/session/dev_demi.h" +#include "util/signal.h" + +static bool is_drm_card(const char *devname) { + const char prefix[] = DRM_PRIMARY_MINOR_NAME; + const char *name = strrchr(devname); + name = name ? name + 1 : devname; + if (strncmp(name, prefix, strlen(prefix)) != 0) { + return false; + } + for (size_t i = strlen(prefix); name[i] != '\0'; i++) { + if (name[i] < '0' || name[i] > '9') { + return false; + } + } + return true; +} + +static int handle_event(int fd, uint32_t mask, void *data) { + struct wlr_session *session = data; + + struct demi_event event; + if (demi_read(fd, &event) == -1) { + // TODO log + return 1; + } + + const char *devname = event.de_devname; + enum demi_event_type event_type = event.de_type; + + if (event_type == DEMI_UNKNOWN) { + // TODO log + return 1; + } + + if (!is_drm_card(devname)) { + // TODO log + return 1; + } + + char devnode[sizeof("/dev/") + sizeof(event.de_devname)]; + snprintf(devnode, sizeof(devnode), "/dev/%s", devname); + + wlr_log(WLR_DEBUG, "kernel event for %s (code %d)", devnode, event_type); + + // TODO https://todo.sr.ht/~kennylevinsen/seatd/1 + const char *seat = "seat0"; + if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { + return 1; + } + + if (event_type == DEMI_ATTACH) { + wlr_log(WLR_DEBUG, "DRM device %s added", devnode); + struct wlr_session_add_event event = { + .path = devnode, + }; + wlr_signal_emit_safe(&session->events.add_drm_card, &event); + } else if (event_type == DEMI_CHANGE || event_type == DEMI_DETACH) { + struct stat st; + // FIXME stat will fail on DEMI_DETACH + if (stat(devnode, &st) == -1) { + // FIXME fallback to comparing devnode + return 1; + } + + struct wlr_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->dev != st.st_rdev) { + continue; + } + + if (event_type == DEMI_CHANGE) { + wlr_log(WLR_DEBUG, "DRM device %s changed", devnode); + // TODO + // struct wlr_device_change_event event = {0}; + // read_udev_change_event(&event, udev_dev); + wlr_signal_emit_safe(&dev->events.change, NULL); + } else if (event_type == DEMI_DETACH) { + wlr_log(WLR_DEBUG, "DRM device %s removed", devnode); + wlr_signal_emit_safe(&dev->events.remove, NULL); + } else { + abort(); + } + break; + } + } + + return 1; +} + +int dev_init(struct wlr_session *session, struct wl_display *disp) { + struct dev *dev = calloc(1, sizeof(*dev)); + if (!dev) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + + dev->fd = demi_init(DEMI_CLOEXEC | DEMI_NONBLOCK); + if (dev->fd == -1) { + wlr_log_errno(WLR_ERROR, "Failed to subscribe to kernel events"); + goto error_dev; + } + + struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); + + dev->event = wl_event_loop_add_fd(event_loop, dev->fd, + WL_EVENT_READABLE, handle_event, session); + if (!dev->event) { + wlr_log_errno(WLR_ERROR, "Failed to create gpu hotplugging event source"); + goto error_fd; + } + + session->dev = dev; + return 0; + +error_fd: + close(dev->fd); +error_dev: + free(dev); + return -1; +} + +void dev_finish(struct wlr_session *session) { + if (!session) { + return; + } + + wl_event_source_remove(session->dev->event); + close(session->dev->fd); + free(session->dev); +} diff --git a/backend/session/meson.build b/backend/session/meson.build index f407a2131..d62784d2b 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -6,17 +6,26 @@ libseat = dependency('libseat', wlr_files += files('session.c') wlr_deps += libseat -# libudev +# libudev & libdemi if get_option('enum-backend') == 'auto' udev = dependency('libudev', required: false) + demi = dependency('demi', required: false) if udev.found() wlr_files += files('dev_udev.c') wlr_deps += udev features += { 'udev': true } + elif demi.found() + wlr_files += files('dev_demi.c') + wlr_deps += demi + features += { 'demi': true } endif elif get_option('enum-backend') == 'udev' wlr_files += files('dev_udev.c') wlr_deps += dependency('libudev') features += { 'udev': true } +elif get_option('enum-backend') == 'demi' + wlr_files += files('dev_demi.c') + wlr_deps += dependency('demi') + features += { 'demi': true } endif diff --git a/backend/session/session.c b/backend/session/session.c index f2917fcad..cd3927fdc 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -145,7 +145,7 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { goto error_open; } -#if WLR_HAS_UDEV +#if WLR_HAS_UDEV || WLR_HAS_DEMI if (dev_init(session, disp) == -1) { wlr_log(WLR_ERROR, "Failed to initialize dev backend"); goto error_session; @@ -159,7 +159,7 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return session; -#if WLR_HAS_UDEV +#if WLR_HAS_UDEV || WLR_HAS_DEMI error_session: libseat_session_finish(session); #endif @@ -176,7 +176,7 @@ void wlr_session_destroy(struct wlr_session *session) { wlr_signal_emit_safe(&session->events.destroy, session); wl_list_remove(&session->display_destroy.link); -#if WLR_HAS_UDEV +#if WLR_HAS_UDEV || WLR_HAS_DEMI dev_finish(session); #endif diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index e636bf5e0..73b81c1bd 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -12,5 +12,6 @@ #mesondefine WLR_HAS_XWAYLAND #mesondefine WLR_HAS_UDEV +#mesondefine WLR_HAS_DEMI #endif diff --git a/meson.build b/meson.build index ec3b734db..12df8e282 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,7 @@ features = { 'gles2-renderer': false, 'vulkan-renderer': false, 'udev': false, + 'demi': false, } internal_features = { 'xcb-errors': false, diff --git a/meson_options.txt b/meson_options.txt index 01eca736e..491dd1e64 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,4 +4,4 @@ option('examples', type: 'boolean', value: true, description: 'Build example app option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') -option('enum-backend', type: 'combo', choices: ['auto', 'disabled', 'udev'], value: 'udev', description: 'Select device enumeration backend') +option('enum-backend', type: 'combo', choices: ['auto', 'disabled', 'udev', 'demi'], value: 'udev', description: 'Select device enumeration backend') From 1e7867610c80347f7aa2e4e3dba63a205df9e2b2 Mon Sep 17 00:00:00 2001 From: illiliti Date: Mon, 14 Mar 2022 00:09:37 +0300 Subject: [PATCH 11/13] backend/session: share is_drm_card implementation --- backend/session/dev.c | 21 +++++++++++++++++++++ backend/session/dev_demi.c | 15 --------------- backend/session/dev_udev.c | 13 ------------- backend/session/meson.build | 2 +- include/backend/session/dev.h | 3 +++ 5 files changed, 25 insertions(+), 29 deletions(-) create mode 100644 backend/session/dev.c diff --git a/backend/session/dev.c b/backend/session/dev.c new file mode 100644 index 000000000..96236dcbb --- /dev/null +++ b/backend/session/dev.c @@ -0,0 +1,21 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "backend/session/dev.h" + +// TODO move to util? +bool is_drm_card(const char *devname) { + const char prefix[] = DRM_PRIMARY_MINOR_NAME; + const char *name = strrchr(devname, '/'); + name = name ? name + 1 : devname; + if (strncmp(name, prefix, strlen(prefix)) != 0) { + return false; + } + for (size_t i = strlen(prefix); name[i] != '\0'; i++) { + if (name[i] < '0' || name[i] > '9') { + return false; + } + } + return true; +} diff --git a/backend/session/dev_demi.c b/backend/session/dev_demi.c index a10b0243d..9a5fed70f 100644 --- a/backend/session/dev_demi.c +++ b/backend/session/dev_demi.c @@ -18,21 +18,6 @@ #include "backend/session/dev_demi.h" #include "util/signal.h" -static bool is_drm_card(const char *devname) { - const char prefix[] = DRM_PRIMARY_MINOR_NAME; - const char *name = strrchr(devname); - name = name ? name + 1 : devname; - if (strncmp(name, prefix, strlen(prefix)) != 0) { - return false; - } - for (size_t i = strlen(prefix); name[i] != '\0'; i++) { - if (name[i] < '0' || name[i] > '9') { - return false; - } - } - return true; -} - static int handle_event(int fd, uint32_t mask, void *data) { struct wlr_session *session = data; diff --git a/backend/session/dev_udev.c b/backend/session/dev_udev.c index 338e43b57..c1cf304ff 100644 --- a/backend/session/dev_udev.c +++ b/backend/session/dev_udev.c @@ -20,19 +20,6 @@ #define WAIT_GPU_TIMEOUT 10000 // ms -static bool is_drm_card(const char *sysname) { - const char prefix[] = DRM_PRIMARY_MINOR_NAME; - if (strncmp(sysname, prefix, strlen(prefix)) != 0) { - return false; - } - for (size_t i = strlen(prefix); sysname[i] != '\0'; i++) { - if (sysname[i] < '0' || sysname[i] > '9') { - return false; - } - } - return true; -} - static void read_udev_change_event(struct wlr_device_change_event *event, struct udev_device *udev_dev) { const char *hotplug = udev_device_get_property_value(udev_dev, "HOTPLUG"); diff --git a/backend/session/meson.build b/backend/session/meson.build index d62784d2b..39fd94125 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -3,7 +3,7 @@ libseat = dependency('libseat', fallback: 'seatd', default_options: ['server=disabled', 'man-pages=disabled'], ) -wlr_files += files('session.c') +wlr_files += files('session.c', 'dev.c') wlr_deps += libseat # libudev & libdemi diff --git a/include/backend/session/dev.h b/include/backend/session/dev.h index 56aae36e1..bae6c14a9 100644 --- a/include/backend/session/dev.h +++ b/include/backend/session/dev.h @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,4 +11,6 @@ void dev_finish(struct wlr_session *session); ssize_t dev_find_gpus(struct wlr_session *session, size_t ret_len, struct wlr_device **ret); + +bool is_drm_card(const char *devname); #endif From 81550bc6d205c410af517d43040003c834b22014 Mon Sep 17 00:00:00 2001 From: illiliti Date: Mon, 21 Mar 2022 09:04:16 +0300 Subject: [PATCH 12/13] backend/session: save devnode in wlr_device --- backend/session/session.c | 7 +++++++ include/wlr/backend/session.h | 1 + 2 files changed, 8 insertions(+) diff --git a/backend/session/session.c b/backend/session/session.c index cd3927fdc..36ac7cb81 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -210,6 +210,12 @@ struct wlr_device *wlr_session_open_file(struct wlr_session *session, goto error; } + dev->devnode = strdup(path); + if (!dev->devnode) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + goto error; + } + dev->fd = fd; dev->dev = st.st_rdev; dev->device_id = device_id; @@ -233,6 +239,7 @@ void wlr_session_close_file(struct wlr_session *session, } close(dev->fd); wl_list_remove(&dev->link); + free(dev->devnode); free(dev); } diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 0f2e09722..0b02b7132 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -12,6 +12,7 @@ struct wlr_device { int fd; int device_id; dev_t dev; + char *devnode; struct wl_list link; struct { From fc455ffa40c7c652bb9795f556e5e2a7f698fc00 Mon Sep 17 00:00:00 2001 From: illiliti Date: Mon, 21 Mar 2022 09:05:26 +0300 Subject: [PATCH 13/13] backend/session/dev_demi.c: compare devnode if devnum is not available --- backend/session/dev_demi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/session/dev_demi.c b/backend/session/dev_demi.c index 9a5fed70f..855d9f4cd 100644 --- a/backend/session/dev_demi.c +++ b/backend/session/dev_demi.c @@ -59,16 +59,18 @@ static int handle_event(int fd, uint32_t mask, void *data) { wlr_signal_emit_safe(&session->events.add_drm_card, &event); } else if (event_type == DEMI_CHANGE || event_type == DEMI_DETACH) { struct stat st; - // FIXME stat will fail on DEMI_DETACH - if (stat(devnode, &st) == -1) { - // FIXME fallback to comparing devnode - return 1; - } + bool has_devnum = stat(devnode, &st) == 0; struct wlr_device *dev; wl_list_for_each(dev, &session->devices, link) { - if (dev->dev != st.st_rdev) { - continue; + if (has_devnum) { + if (dev->dev != st.st_rdev) { + continue; + } + } else { + if (strcmp(dev->devnode, devnode) != 0) { + continue; + } } if (event_type == DEMI_CHANGE) {