From 46823152ea5e2d0f888fa25ba6b4b1896e4e89b9 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 26 Aug 2017 11:56:43 +1200 Subject: [PATCH 1/3] Rename functions to be consistent with #93 --- backend/backend.c | 4 ++-- backend/multi/backend.c | 2 +- backend/session/direct-ipc.c | 2 +- backend/session/direct.c | 10 +++++----- backend/session/logind.c | 8 ++++---- backend/session/session.c | 8 ++++---- include/backend/session/direct-ipc.h | 2 +- include/wlr/backend/session.h | 4 ++-- include/wlr/backend/session/interface.h | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/backend/backend.c b/backend/backend.c index 790a14b3..9a3fd036 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -85,7 +85,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { // Attempt DRM+libinput - struct wlr_session *session = wlr_session_start(display); + struct wlr_session *session = wlr_session_create(display); if (!session) { wlr_log(L_ERROR, "Failed to start a DRM session"); return NULL; @@ -131,6 +131,6 @@ error_gpu: error_udev: wlr_udev_destroy(udev); error_session: - wlr_session_finish(session); + wlr_session_destroy(session); return NULL; } diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 33b26a0a..9bb596e5 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -36,7 +36,7 @@ static void multi_backend_destroy(struct wlr_backend *_backend) { free(sub); } list_free(backend->backends); - wlr_session_finish(backend->session); + wlr_session_destroy(backend->session); wlr_udev_destroy(backend->udev); free(backend); } diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 71e22148..5f1494a6 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -212,7 +212,7 @@ void direct_ipc_finish(int sock, pid_t pid) { waitpid(pid, NULL, 0); } -int direct_ipc_start(pid_t *pid_out) { +int direct_ipc_init(pid_t *pid_out) { if (!have_permissions()) { return -1; } diff --git a/backend/session/direct.c b/backend/session/direct.c index 82aa8e00..0a08bfd6 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -79,7 +79,7 @@ static bool direct_change_vt(struct wlr_session *base, unsigned vt) { return ioctl(session->tty_fd, VT_ACTIVATE, (int)vt) == 0; } -static void direct_session_finish(struct wlr_session *base) { +static void direct_session_destroy(struct wlr_session *base) { struct direct_session *session = wl_container_of(base, session, base); struct vt_mode mode = { .mode = VT_AUTO, @@ -196,14 +196,14 @@ error: return false; } -static struct wlr_session *direct_session_start(struct wl_display *disp) { +static struct wlr_session *direct_session_create(struct wl_display *disp) { struct direct_session *session = calloc(1, sizeof(*session)); if (!session) { wlr_log_errno(L_ERROR, "Allocation failed"); return NULL; } - session->sock = direct_ipc_start(&session->child); + session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; } @@ -236,8 +236,8 @@ error_session: } const struct session_impl session_direct = { - .start = direct_session_start, - .finish = direct_session_finish, + .create = direct_session_create, + .destroy = direct_session_destroy, .open = direct_session_open, .close = direct_session_close, .change_vt = direct_change_vt, diff --git a/backend/session/logind.c b/backend/session/logind.c index 20d9b5ed..6b93ff67 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -204,7 +204,7 @@ static void release_control(struct logind_session *session) { sd_bus_message_unref(msg); } -static void logind_session_finish(struct wlr_session *base) { +static void logind_session_destroy(struct wlr_session *base) { struct logind_session *session = wl_container_of(base, session, base); release_control(session); @@ -316,7 +316,7 @@ static int dbus_event(int fd, uint32_t mask, void *data) { return 1; } -static struct wlr_session *logind_session_start(struct wl_display *disp) { +static struct wlr_session *logind_session_create(struct wl_display *disp) { int ret; struct logind_session *session = calloc(1, sizeof(*session)); if (!session) { @@ -390,8 +390,8 @@ error: } const struct session_impl session_logind = { - .start = logind_session_start, - .finish = logind_session_finish, + .create = logind_session_create, + .destroy = logind_session_destroy, .open = logind_take_device, .close = logind_release_device, .change_vt = logind_change_vt, diff --git a/backend/session/session.c b/backend/session/session.c index a07d3cda..24a1f538 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -15,11 +15,11 @@ static const struct session_impl *impls[] = { NULL, }; -struct wlr_session *wlr_session_start(struct wl_display *disp) { +struct wlr_session *wlr_session_create(struct wl_display *disp) { const struct session_impl **iter; for (iter = impls; *iter; ++iter) { - struct wlr_session *session = (*iter)->start(disp); + struct wlr_session *session = (*iter)->create(disp); if (session) { return session; } @@ -29,12 +29,12 @@ struct wlr_session *wlr_session_start(struct wl_display *disp) { return NULL; } -void wlr_session_finish(struct wlr_session *session) { +void wlr_session_destroy(struct wlr_session *session) { if (!session) { return; } - session->impl->finish(session); + session->impl->destroy(session); }; int wlr_session_open_file(struct wlr_session *session, const char *path) { diff --git a/include/backend/session/direct-ipc.h b/include/backend/session/direct-ipc.h index 96504f04..2189d6fa 100644 --- a/include/backend/session/direct-ipc.h +++ b/include/backend/session/direct-ipc.h @@ -7,6 +7,6 @@ int direct_ipc_open(int sock, const char *path); void direct_ipc_setmaster(int sock, int fd); void direct_ipc_dropmaster(int sock, int fd); void direct_ipc_finish(int sock, pid_t pid); -int direct_ipc_start(pid_t *pid_out); +int direct_ipc_init(pid_t *pid_out); #endif diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 7961e620..24854431 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -31,14 +31,14 @@ struct wlr_session { * * Returns NULL on error. */ -struct wlr_session *wlr_session_start(struct wl_display *disp); +struct wlr_session *wlr_session_create(struct wl_display *disp); /* * Closes a previously opened session and restores the virtual terminal. * You should call wlr_session_close_file on each files you opened * with wlr_session_open_file before you call this. */ -void wlr_session_finish(struct wlr_session *session); +void wlr_session_destroy(struct wlr_session *session); /* * Opens the file at path. diff --git a/include/wlr/backend/session/interface.h b/include/wlr/backend/session/interface.h index 16814446..1a029c54 100644 --- a/include/wlr/backend/session/interface.h +++ b/include/wlr/backend/session/interface.h @@ -4,8 +4,8 @@ #include struct session_impl { - struct wlr_session *(*start)(struct wl_display *disp); - void (*finish)(struct wlr_session *session); + struct wlr_session *(*create)(struct wl_display *disp); + void (*destroy)(struct wlr_session *session); int (*open)(struct wlr_session *session, const char *path); void (*close)(struct wlr_session *session, int fd); bool (*change_vt)(struct wlr_session *session, unsigned vt); From fb93628bda0cb7750628e227213a1ddc2ae34be9 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 26 Aug 2017 14:02:04 +1200 Subject: [PATCH 2/3] Merge wlr_udev into wlr_session --- backend/backend.c | 21 +-- backend/drm/backend.c | 9 +- backend/libinput/backend.c | 8 +- backend/meson.build | 1 - backend/multi/backend.c | 6 +- backend/session/direct.c | 2 - backend/session/logind.c | 2 - backend/session/session.c | 275 +++++++++++++++++++++++++++++++-- backend/udev.c | 252 ------------------------------ include/backend/drm.h | 3 - include/backend/libinput.h | 2 - include/backend/multi.h | 2 - include/backend/udev.h | 29 ---- include/wlr/backend/drm.h | 3 +- include/wlr/backend/libinput.h | 3 +- include/wlr/backend/multi.h | 4 +- include/wlr/backend/session.h | 11 ++ include/wlr/backend/udev.h | 9 -- 18 files changed, 292 insertions(+), 350 deletions(-) delete mode 100644 backend/udev.c delete mode 100644 include/backend/udev.h delete mode 100644 include/wlr/backend/udev.h diff --git a/backend/backend.c b/backend/backend.c index 9a3fd036..88b9dfbc 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -12,7 +12,6 @@ #include #include #include -#include "backend/udev.h" void wlr_backend_init(struct wlr_backend *backend, const struct wlr_backend_impl *impl) { @@ -91,29 +90,23 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { return NULL; } - struct wlr_udev *udev = wlr_udev_create(display); - if (!udev) { - wlr_log(L_ERROR, "Failed to start udev"); + int gpu = wlr_session_find_gpu(session); + if (gpu == -1) { + wlr_log(L_ERROR, "Failed to open DRM device"); goto error_session; } - int gpu = wlr_udev_find_gpu(udev, session); - if (gpu == -1) { - wlr_log(L_ERROR, "Failed to open DRM device"); - goto error_udev; - } - - backend = wlr_multi_backend_create(session, udev); + backend = wlr_multi_backend_create(session); if (!backend) { goto error_gpu; } - struct wlr_backend *libinput = wlr_libinput_backend_create(display, session, udev); + struct wlr_backend *libinput = wlr_libinput_backend_create(display, session); if (!libinput) { goto error_multi; } - struct wlr_backend *drm = wlr_drm_backend_create(display, session, udev, gpu); + struct wlr_backend *drm = wlr_drm_backend_create(display, session, gpu); if (!drm) { goto error_libinput; } @@ -128,8 +121,6 @@ error_multi: wlr_backend_destroy(backend); error_gpu: wlr_session_close_file(session, gpu); -error_udev: - wlr_udev_destroy(udev); error_session: wlr_session_destroy(session); return NULL; diff --git a/backend/drm/backend.c b/backend/drm/backend.c index a84130ee..68e73268 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -13,7 +13,6 @@ #include #include #include -#include "backend/udev.h" #include "backend/drm.h" static bool wlr_drm_backend_start(struct wlr_backend *_backend) { @@ -32,7 +31,6 @@ static void wlr_drm_backend_destroy(struct wlr_backend *_backend) { wlr_output_destroy(&output->output); } - wlr_udev_signal_remove(backend->udev, &backend->drm_invalidated); wlr_drm_renderer_free(&backend->renderer); wlr_drm_resources_free(backend); wlr_session_close_file(backend->session, backend->fd); @@ -84,8 +82,6 @@ static void session_signal(struct wl_listener *listener, void *data) { static void drm_invalidated(struct wl_listener *listener, void *data) { struct wlr_drm_backend *backend = wl_container_of(listener, backend, drm_invalidated); - struct wlr_udev *udev = data; - (void)udev; char *name = drmGetDeviceNameFromFd2(backend->fd); wlr_log(L_DEBUG, "%s invalidated", name); @@ -95,7 +91,7 @@ static void drm_invalidated(struct wl_listener *listener, void *data) { } struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, - struct wlr_session *session, struct wlr_udev *udev, int gpu_fd) { + struct wlr_session *session, int gpu_fd) { assert(display && session && gpu_fd >= 0); char *name = drmGetDeviceNameFromFd2(gpu_fd); @@ -112,7 +108,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, wlr_backend_init(&backend->backend, &backend_impl); backend->session = session; - backend->udev = udev; backend->outputs = list_create(); if (!backend->outputs) { wlr_log(L_ERROR, "Failed to allocate list"); @@ -128,7 +123,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, backend->dev = st.st_rdev; backend->drm_invalidated.notify = drm_invalidated; - wlr_udev_signal_add(udev, backend->dev, &backend->drm_invalidated); + wlr_session_signal_add(session, gpu_fd, &backend->drm_invalidated); backend->display = display; struct wl_event_loop *event_loop = wl_display_get_event_loop(display); diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 5dd93f47..3d3c90ce 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -4,7 +4,6 @@ #include #include #include -#include "backend/udev.h" #include "backend/libinput.h" static int wlr_libinput_open_restricted(const char *path, @@ -47,7 +46,7 @@ static bool wlr_libinput_backend_start(struct wlr_backend *_backend) { struct wlr_libinput_backend *backend = (struct wlr_libinput_backend *)_backend; wlr_log(L_DEBUG, "Initializing libinput"); backend->libinput_context = libinput_udev_create_context(&libinput_impl, backend, - backend->udev->udev); + backend->session->udev); if (!backend->libinput_context) { wlr_log(L_ERROR, "Failed to create libinput context"); return false; @@ -139,8 +138,8 @@ static void session_signal(struct wl_listener *listener, void *data) { } struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, - struct wlr_session *session, struct wlr_udev *udev) { - assert(display && session && udev); + struct wlr_session *session) { + assert(display && session); struct wlr_libinput_backend *backend = calloc(1, sizeof(struct wlr_libinput_backend)); if (!backend) { @@ -155,7 +154,6 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, } backend->session = session; - backend->udev = udev; backend->display = display; backend->session_signal.notify = session_signal; diff --git a/backend/meson.build b/backend/meson.build index 6a6a5f9f..fcff55b6 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -1,6 +1,5 @@ backend_files = files( 'backend.c', - 'udev.c', 'session/direct-ipc.c', 'session/direct.c', 'session/session.c', diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 9bb596e5..5f745c40 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include "backend/multi.h" @@ -37,7 +36,6 @@ static void multi_backend_destroy(struct wlr_backend *_backend) { } list_free(backend->backends); wlr_session_destroy(backend->session); - wlr_udev_destroy(backend->udev); free(backend); } @@ -59,8 +57,7 @@ struct wlr_backend_impl backend_impl = { .get_egl = multi_backend_get_egl }; -struct wlr_backend *wlr_multi_backend_create(struct wlr_session *session, - struct wlr_udev *udev) { +struct wlr_backend *wlr_multi_backend_create(struct wlr_session *session) { struct wlr_multi_backend *backend = calloc(1, sizeof(struct wlr_multi_backend)); if (!backend) { @@ -78,7 +75,6 @@ struct wlr_backend *wlr_multi_backend_create(struct wlr_session *session, wlr_backend_init(&backend->backend, &backend_impl); backend->session = session; - backend->udev = udev; return &backend->backend; } diff --git a/backend/session/direct.c b/backend/session/direct.c index 0a08bfd6..4eff10e1 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -223,8 +223,6 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.drm_fd = -1; session->base.impl = &session_direct; - session->base.active = true; - wl_signal_init(&session->base.session_signal); return &session->base; error_ipc: diff --git a/backend/session/logind.c b/backend/session/logind.c index 6b93ff67..c5465936 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -376,8 +376,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { session->base.drm_fd = -1; session->base.impl = &session_logind; - session->base.active = true; - wl_signal_init(&session->base.session_signal); return &session->base; error_bus: diff --git a/backend/session/session.c b/backend/session/session.c index 24a1f538..26b9aa92 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -1,9 +1,25 @@ +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include +struct device { + int fd; + dev_t dev; + struct wl_signal signal; + + struct wl_list link; +}; + extern const struct session_impl session_logind; extern const struct session_impl session_direct; @@ -15,17 +31,88 @@ static const struct session_impl *impls[] = { NULL, }; -struct wlr_session *wlr_session_create(struct wl_display *disp) { - const struct session_impl **iter; +static int udev_event(int fd, uint32_t mask, void *data) { + struct wlr_session *session = data; - for (iter = impls; *iter; ++iter) { - struct wlr_session *session = (*iter)->create(disp); - if (session) { - return session; + struct udev_device *udev_dev = udev_monitor_receive_device(session->mon); + if (!udev_dev) { + return 1; + } + + const char *action = udev_device_get_action(udev_dev); + + wlr_log(L_DEBUG, "udev event for %s (%s)", + udev_device_get_sysname(udev_dev), action); + + if (!action || strcmp(action, "change") != 0) { + goto out; + } + + dev_t devnum = udev_device_get_devnum(udev_dev); + struct device *dev; + + wl_list_for_each(dev, &session->devices, link) { + if (dev->dev == devnum) { + wl_signal_emit(&dev->signal, session); + break; } } - wlr_log(L_ERROR, "Failed to load session backend"); +out: + udev_device_unref(udev_dev); + return 1; +} + +struct wlr_session *wlr_session_create(struct wl_display *disp) { + struct wlr_session *session = NULL; + const struct session_impl **iter; + + for (iter = impls; !session && *iter; ++iter) { + session = (*iter)->create(disp); + } + + if (!session) { + wlr_log(L_ERROR, "Failed to load session backend"); + return NULL; + } + + session->active = true; + wl_signal_init(&session->session_signal); + wl_list_init(&session->devices); + + session->udev = udev_new(); + if (!session->udev) { + wlr_log_errno(L_ERROR, "Failed to create udev context"); + goto error_session; + } + + session->mon = udev_monitor_new_from_netlink(session->udev, "udev"); + if (!session->mon) { + wlr_log_errno(L_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, udev_event, session); + if (!session->udev_event) { + wlr_log_errno(L_ERROR, "Failed to create udev event source"); + goto error_mon; + } + + return session; + +error_mon: + udev_monitor_unref(session->mon); +error_udev: + udev_unref(session->udev); +error_session: + wlr_session_destroy(session); return NULL; } @@ -34,15 +121,69 @@ void wlr_session_destroy(struct wlr_session *session) { return; } + wl_event_source_remove(session->udev_event); + udev_monitor_unref(session->mon); + udev_unref(session->udev); + session->impl->destroy(session); -}; +} int wlr_session_open_file(struct wlr_session *session, const char *path) { - return session->impl->open(session, path); + int fd = session->impl->open(session, path); + if (fd < 0) { + return fd; + } + + struct device *dev = malloc(sizeof(*dev)); + if (!dev) { + wlr_log_errno(L_ERROR, "Allocation failed"); + goto error; + } + + struct stat st; + if (fstat(fd, &st) < 0) { + wlr_log_errno(L_ERROR, "Stat failed"); + goto error; + } + + dev->fd = fd; + dev->dev = st.st_rdev; + wl_signal_init(&dev->signal); + wl_list_insert(&session->devices, &dev->link); + + return fd; + +error: + free(dev); + return fd; +} + +static struct device *find_device(struct wlr_session *session, int fd) { + struct device *dev; + + wl_list_for_each(dev, &session->devices, link) { + if (dev->fd == fd) { + return dev; + } + } + + wlr_log(L_ERROR, "Tried to use fd %d not opened by session", fd); + assert(0); } void wlr_session_close_file(struct wlr_session *session, int fd) { + struct device *dev = find_device(session, fd); + session->impl->close(session, fd); + wl_list_remove(&dev->link); + free(dev); +} + +void wlr_session_signal_add(struct wlr_session *session, int fd, + struct wl_listener *listener) { + struct device *dev = find_device(session, fd); + + wl_signal_add(&dev->signal, listener); } bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { @@ -52,3 +193,119 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { return session->impl->change_vt(session, vt); } + +/* Tests if 'path' is KMS compatible by trying to open it. + * It leaves the open device in *fd_out it it succeeds. + */ +static bool device_is_kms(struct wlr_session *restrict session, + const char *restrict path, int *restrict fd_out) { + + int fd; + + if (!path) { + return false; + } + + fd = wlr_session_open_file(session, path); + if (fd < 0) { + return false; + } + + drmModeRes *res = drmModeGetResources(fd); + if (!res) { + goto out_fd; + } + + if (res->count_crtcs <= 0 || res->count_connectors <= 0 || + res->count_encoders <= 0) { + + goto out_res; + } + + if (*fd_out >= 0) { + wlr_session_close_file(session, *fd_out); + } + + *fd_out = fd; + + drmModeFreeResources(res); + return true; + +out_res: + drmModeFreeResources(res); +out_fd: + wlr_session_close_file(session, fd); + return false; +} + +/* 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. + */ +int wlr_session_find_gpu(struct wlr_session *session) { + struct udev_enumerate *en = udev_enumerate_new(session->udev); + if (!en) { + wlr_log(L_ERROR, "Failed to create udev enumeration"); + return -1; + } + + udev_enumerate_add_match_subsystem(en, "drm"); + udev_enumerate_add_match_sysname(en, "card[0-9]*"); + udev_enumerate_scan_devices(en); + + struct udev_list_entry *entry; + int fd = -1; + + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { + 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 (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; + } + } + + // We already have a valid GPU + if (!is_boot_vga && fd >= 0) { + udev_device_unref(dev); + continue; + } + + path = udev_device_get_devnode(dev); + if (!device_is_kms(session, path, &fd)) { + udev_device_unref(dev); + continue; + } + + udev_device_unref(dev); + + // We've found the primary GPU + if (is_boot_vga) { + break; + } + } + + udev_enumerate_unref(en); + + return fd; +} diff --git a/backend/udev.c b/backend/udev.c deleted file mode 100644 index a2492172..00000000 --- a/backend/udev.c +++ /dev/null @@ -1,252 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "backend/udev.h" - -/* Tests if 'path' is KMS compatible by trying to open it. - * It leaves the open device in *fd_out it it succeeds. - */ -static bool device_is_kms(struct wlr_session *restrict session, - const char *restrict path, int *restrict fd_out) { - - int fd; - - if (!path) { - return false; - } - - fd = wlr_session_open_file(session, path); - if (fd < 0) { - return false; - } - - drmModeRes *res = drmModeGetResources(fd); - if (!res) { - goto out_fd; - } - - if (res->count_crtcs <= 0 || res->count_connectors <= 0 || - res->count_encoders <= 0) { - - goto out_res; - } - - if (*fd_out >= 0) { - wlr_session_close_file(session, *fd_out); - } - - *fd_out = fd; - - drmModeFreeResources(res); - return true; - -out_res: - drmModeFreeResources(res); -out_fd: - wlr_session_close_file(session, fd); - return false; -} - -/* 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. - */ -int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session) { - struct udev_enumerate *en = udev_enumerate_new(udev->udev); - if (!en) { - wlr_log(L_ERROR, "Failed to create udev enumeration"); - return -1; - } - - udev_enumerate_add_match_subsystem(en, "drm"); - udev_enumerate_add_match_sysname(en, "card[0-9]*"); - udev_enumerate_scan_devices(en); - - struct udev_list_entry *entry; - int fd = -1; - - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { - bool is_boot_vga = false; - - const char *path = udev_list_entry_get_name(entry); - struct udev_device *dev = udev_device_new_from_syspath(udev->udev, path); - if (!dev) { - continue; - } - - /* - const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); - if (!seat) - seat = "seat0"; - if (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; - } - } - - // We already have a valid GPU - if (!is_boot_vga && fd >= 0) { - udev_device_unref(dev); - continue; - } - - path = udev_device_get_devnode(dev); - if (!device_is_kms(session, path, &fd)) { - udev_device_unref(dev); - continue; - } - - udev_device_unref(dev); - - // We've found the primary GPU - if (is_boot_vga) { - break; - } - } - - udev_enumerate_unref(en); - - return fd; -} - -static int udev_event(int fd, uint32_t mask, void *data) { - struct wlr_udev *udev = data; - - struct udev_device *dev = udev_monitor_receive_device(udev->mon); - if (!dev) { - return 1; - } - - const char *action = udev_device_get_action(dev); - - wlr_log(L_DEBUG, "udev event for %s (%s)", - udev_device_get_sysname(dev), action); - - if (!action || strcmp(action, "change") != 0) { - goto out; - } - - dev_t devnum = udev_device_get_devnum(dev); - struct wlr_udev_dev *signal; - - wl_list_for_each(signal, &udev->devices, link) { - if (signal->dev == devnum) { - wl_signal_emit(&signal->invalidate, udev); - break; - } - } - -out: - udev_device_unref(dev); - return 1; -} - -struct wlr_udev *wlr_udev_create(struct wl_display *display) { - struct wlr_udev *udev = calloc(sizeof(struct wlr_udev), 1); - if (!udev) { - return NULL; - } - udev->udev = udev_new(); - if (!udev->udev) { - wlr_log(L_ERROR, "Failed to create udev context"); - goto error; - } - - udev->mon = udev_monitor_new_from_netlink(udev->udev, "udev"); - if (!udev->mon) { - wlr_log(L_ERROR, "Failed to create udev monitor"); - goto error_udev; - } - - udev_monitor_filter_add_match_subsystem_devtype(udev->mon, "drm", NULL); - udev_monitor_enable_receiving(udev->mon); - - struct wl_event_loop *event_loop = wl_display_get_event_loop(display); - int fd = udev_monitor_get_fd(udev->mon); - - udev->event = wl_event_loop_add_fd(event_loop, fd, WL_EVENT_READABLE, - udev_event, udev); - if (!udev->event) { - wlr_log(L_ERROR, "Failed to create udev event source"); - goto error_mon; - } - - wl_list_init(&udev->devices); - - wlr_log(L_DEBUG, "Successfully initialized udev"); - return udev; - -error_mon: - udev_monitor_unref(udev->mon); -error_udev: - udev_unref(udev->udev); -error: - free(udev); - return NULL; -} - -void wlr_udev_destroy(struct wlr_udev *udev) { - if (!udev) { - return; - } - - struct wlr_udev_dev *dev, *tmp; - wl_list_for_each_safe(dev, tmp, &udev->devices, link) { - free(dev); - } - - wl_event_source_remove(udev->event); - udev_monitor_unref(udev->mon); - udev_unref(udev->udev); - free(udev); -} - -bool wlr_udev_signal_add(struct wlr_udev *udev, dev_t dev, struct wl_listener *listener) { - struct wlr_udev_dev *device = malloc(sizeof(*device)); - if (!device) { - wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); - return false; - } - - device->dev = dev; - wl_signal_init(&device->invalidate); - wl_signal_add(&device->invalidate, listener); - wl_list_insert(&udev->devices, &device->link); - - return true; -} - -void wlr_udev_signal_remove(struct wlr_udev *udev, struct wl_listener *listener) { - if (!udev || !listener) { - return; - } - - struct wlr_udev_dev *dev, *tmp; - wl_list_for_each_safe(dev, tmp, &udev->devices, link) { - // The signal should only have a single listener - if (wl_signal_get(&dev->invalidate, listener->notify) != NULL) { - wl_list_remove(&dev->link); - free(dev); - return; - } - } -} diff --git a/include/backend/drm.h b/include/backend/drm.h index 25bbd1f7..342a980c 100644 --- a/include/backend/drm.h +++ b/include/backend/drm.h @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -16,7 +15,6 @@ #include #include -#include #include "drm-properties.h" struct wlr_drm_plane { @@ -124,7 +122,6 @@ struct wlr_drm_backend { struct wlr_drm_renderer renderer; struct wlr_session *session; - struct wlr_udev *udev; }; enum wlr_drm_output_state { diff --git a/include/backend/libinput.h b/include/backend/libinput.h index e0f762a7..f484ea8d 100644 --- a/include/backend/libinput.h +++ b/include/backend/libinput.h @@ -6,13 +6,11 @@ #include #include #include -#include "backend/udev.h" struct wlr_libinput_backend { struct wlr_backend backend; struct wlr_session *session; - struct wlr_udev *udev; struct wl_display *display; struct libinput *libinput_context; diff --git a/include/backend/multi.h b/include/backend/multi.h index af747332..c7a2198e 100644 --- a/include/backend/multi.h +++ b/include/backend/multi.h @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -11,7 +10,6 @@ struct wlr_multi_backend { struct wlr_backend backend; struct wlr_session *session; - struct wlr_udev *udev; list_t *backends; }; diff --git a/include/backend/udev.h b/include/backend/udev.h deleted file mode 100644 index 080422c0..00000000 --- a/include/backend/udev.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _WLR_INTERNAL_UDEV_H -#define _WLR_INTERNAL_UDEV_H - -#include -#include -#include -#include -#include - -struct wlr_udev_dev { - dev_t dev; - struct wl_signal invalidate; - - struct wl_list link; -}; - -struct wlr_udev { - struct udev *udev; - struct udev_monitor *mon; - struct wl_event_source *event; - - struct wl_list devices; -}; - -int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session); -bool wlr_udev_signal_add(struct wlr_udev *udev, dev_t dev, struct wl_listener *listener); -void wlr_udev_signal_remove(struct wlr_udev *udev, struct wl_listener *listener); - -#endif diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index fe1cc5a7..fa63df0a 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -4,10 +4,9 @@ #include #include #include -#include struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, - struct wlr_session *session, struct wlr_udev *udev, int gpu_fd); + struct wlr_session *session, int gpu_fd); bool wlr_backend_is_drm(struct wlr_backend *backend); diff --git a/include/wlr/backend/libinput.h b/include/wlr/backend/libinput.h index b227a7ad..95b8829d 100644 --- a/include/wlr/backend/libinput.h +++ b/include/wlr/backend/libinput.h @@ -5,11 +5,10 @@ #include #include #include -#include #include struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, - struct wlr_session *session, struct wlr_udev *udev); + struct wlr_session *session); struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev); bool wlr_backend_is_libinput(struct wlr_backend *backend); diff --git a/include/wlr/backend/multi.h b/include/wlr/backend/multi.h index e8e46bed..3fcaaf1e 100644 --- a/include/wlr/backend/multi.h +++ b/include/wlr/backend/multi.h @@ -2,11 +2,9 @@ #define _WLR_BACKEND_MULTI_H #include -#include #include -struct wlr_backend *wlr_multi_backend_create(struct wlr_session *session, - struct wlr_udev *udev); +struct wlr_backend *wlr_multi_backend_create(struct wlr_session *session); void wlr_multi_backend_add(struct wlr_backend *multi, struct wlr_backend *backend); diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 24854431..fbdc97fc 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -3,6 +3,7 @@ #include #include +#include #include struct session_impl; @@ -19,6 +20,12 @@ struct wlr_session { int drm_fd; unsigned vtnr; char seat[8]; + + struct udev *udev; + struct udev_monitor *mon; + struct wl_event_source *udev_event; + + struct wl_list devices; }; /* @@ -57,9 +64,13 @@ int wlr_session_open_file(struct wlr_session *session, const char *path); */ void wlr_session_close_file(struct wlr_session *session, int fd); +void wlr_session_signal_add(struct wlr_session *session, int fd, + struct wl_listener *listener); /* * Changes the virtual terminal. */ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt); +int wlr_session_find_gpu(struct wlr_session *session); + #endif diff --git a/include/wlr/backend/udev.h b/include/wlr/backend/udev.h deleted file mode 100644 index 387a63e6..00000000 --- a/include/wlr/backend/udev.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _WLR_BACKEND_UDEV_H -#define _WLR_BACKEND_UDEV_H - -struct wlr_udev; - -struct wlr_udev *wlr_udev_create(struct wl_display *display); -void wlr_udev_destroy(struct wlr_udev *udev); - -#endif From d16b2977f6b156e5b3a4ceb028cfbe70b9a350c1 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 26 Aug 2017 14:50:16 +1200 Subject: [PATCH 3/3] Remove single GPU assumptions from wlr_session --- backend/session/direct.c | 26 ++++++++++++++++++++------ backend/session/logind.c | 34 ++++++++++++++++++++++------------ backend/session/session.c | 20 ++++++-------------- include/wlr/backend/session.h | 9 ++++++++- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/backend/session/direct.c b/backend/session/direct.c index 4eff10e1..942dc552 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -48,7 +48,7 @@ static int direct_session_open(struct wlr_session *base, const char *path) { } if (major(st.st_rdev) == DRM_MAJOR) { - session->base.drm_fd = fd; + direct_ipc_setmaster(session->sock, fd); } return fd; @@ -65,8 +65,7 @@ static void direct_session_close(struct wlr_session *base, int fd) { } if (major(st.st_rdev) == DRM_MAJOR) { - direct_ipc_dropmaster(session->sock, session->base.drm_fd); - session->base.drm_fd = -1; + direct_ipc_dropmaster(session->sock, fd); } else if (major(st.st_rdev) == INPUT_MAJOR) { ioctl(fd, EVIOCREVOKE, 0); } @@ -109,11 +108,27 @@ static int vt_handler(int signo, void *data) { if (session->base.active) { session->base.active = false; wl_signal_emit(&session->base.session_signal, session); - direct_ipc_dropmaster(session->sock, session->base.drm_fd); + + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + if (major(dev->dev) == DRM_MAJOR) { + direct_ipc_dropmaster(session->sock, + dev->fd); + } + } + ioctl(session->tty_fd, VT_RELDISP, 1); } else { ioctl(session->tty_fd, VT_RELDISP, VT_ACKACQ); - direct_ipc_setmaster(session->sock, session->base.drm_fd); + + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + if (major(dev->dev) == DRM_MAJOR) { + direct_ipc_setmaster(session->sock, + dev->fd); + } + } + session->base.active = true; wl_signal_emit(&session->base.session_signal, session); } @@ -221,7 +236,6 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { wlr_log(L_INFO, "Successfully loaded direct session"); snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); - session->base.drm_fd = -1; session->base.impl = &session_direct; return &session->base; diff --git a/backend/session/logind.c b/backend/session/logind.c index c5465936..3b237360 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -67,10 +68,6 @@ static int logind_take_device(struct wlr_session *base, const char *path) { goto error; } - if (major(st.st_rdev) == DRM_MAJOR) { - session->base.drm_fd = fd; - } - error: sd_bus_error_free(&error); sd_bus_message_unref(msg); @@ -97,10 +94,6 @@ static void logind_release_device(struct wlr_session *base, int fd) { wlr_log(L_ERROR, "Failed to release device '%d'", fd); } - if (major(st.st_rdev) == DRM_MAJOR) { - session->base.drm_fd = -1; - } - sd_bus_error_free(&error); sd_bus_message_unref(msg); } @@ -221,6 +214,20 @@ static int session_removed(sd_bus_message *msg, void *userdata, sd_bus_error *re return 0; } +static struct wlr_device *find_device(struct wlr_session *session, dev_t devnum) { + struct wlr_device *dev; + + wl_list_for_each(dev, &session->devices, link) { + if (dev->dev == devnum) { + return dev; + } + } + + wlr_log(L_ERROR, "Tried to use dev_t %lu not opened by session", + (unsigned long)devnum); + assert(0); +} + static int pause_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) { struct logind_session *session = userdata; int ret; @@ -267,9 +274,13 @@ static int resume_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_ } if (major == DRM_MAJOR) { - dup2(fd, session->base.drm_fd); - session->base.active = true; - wl_signal_emit(&session->base.session_signal, session); + struct wlr_device *dev = find_device(&session->base, makedev(major, minor)); + dup2(fd, dev->fd); + + if (!session->base.active) { + session->base.active = true; + wl_signal_emit(&session->base.session_signal, session); + } } error: @@ -374,7 +385,6 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { wlr_log(L_INFO, "Successfully loaded logind session"); - session->base.drm_fd = -1; session->base.impl = &session_logind; return &session->base; diff --git a/backend/session/session.c b/backend/session/session.c index 26b9aa92..c9bc1397 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -12,14 +12,6 @@ #include #include -struct device { - int fd; - dev_t dev; - struct wl_signal signal; - - struct wl_list link; -}; - extern const struct session_impl session_logind; extern const struct session_impl session_direct; @@ -49,7 +41,7 @@ static int udev_event(int fd, uint32_t mask, void *data) { } dev_t devnum = udev_device_get_devnum(udev_dev); - struct device *dev; + struct wlr_device *dev; wl_list_for_each(dev, &session->devices, link) { if (dev->dev == devnum) { @@ -134,7 +126,7 @@ int wlr_session_open_file(struct wlr_session *session, const char *path) { return fd; } - struct device *dev = malloc(sizeof(*dev)); + struct wlr_device *dev = malloc(sizeof(*dev)); if (!dev) { wlr_log_errno(L_ERROR, "Allocation failed"); goto error; @@ -158,8 +150,8 @@ error: return fd; } -static struct device *find_device(struct wlr_session *session, int fd) { - struct device *dev; +static struct wlr_device *find_device(struct wlr_session *session, int fd) { + struct wlr_device *dev; wl_list_for_each(dev, &session->devices, link) { if (dev->fd == fd) { @@ -172,7 +164,7 @@ static struct device *find_device(struct wlr_session *session, int fd) { } void wlr_session_close_file(struct wlr_session *session, int fd) { - struct device *dev = find_device(session, fd); + struct wlr_device *dev = find_device(session, fd); session->impl->close(session, fd); wl_list_remove(&dev->link); @@ -181,7 +173,7 @@ void wlr_session_close_file(struct wlr_session *session, int fd) { void wlr_session_signal_add(struct wlr_session *session, int fd, struct wl_listener *listener) { - struct device *dev = find_device(session, fd); + struct wlr_device *dev = find_device(session, fd); wl_signal_add(&dev->signal, listener); } diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index fbdc97fc..04e701b0 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -8,6 +8,14 @@ struct session_impl; +struct wlr_device { + int fd; + dev_t dev; + struct wl_signal signal; + + struct wl_list link; +}; + struct wlr_session { const struct session_impl *impl; /* @@ -17,7 +25,6 @@ struct wlr_session { struct wl_signal session_signal; bool active; - int drm_fd; unsigned vtnr; char seat[8];