diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 3031d09b..64db81f5 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1554,17 +1554,13 @@ int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend) { return fd; } -/* TODO: make the function return a `wlr_drm_lease` to provide a destroy event - * that can be fired when the kernel notifies us through uevent that the lease - * has been destroyed - */ -int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, - uint32_t *lessee_id) { +struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, + size_t n_outputs, int *lease_fd_ptr) { assert(outputs); if (n_outputs == 0) { wlr_log(WLR_ERROR, "Can't lease 0 outputs"); - return -1; + return NULL; } struct wlr_drm_backend *drm = @@ -1575,11 +1571,11 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, for (size_t i = 0; i < n_outputs; ++i) { struct wlr_drm_connector *conn = get_drm_connector_from_output(outputs[i]); - assert(conn->lessee_id == 0); + assert(conn->lease == NULL); if (conn->backend != drm) { wlr_log(WLR_ERROR, "Can't lease output from different backends"); - return -1; + return NULL; } objects[n_objects++] = conn->id; @@ -1587,7 +1583,7 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, if (!conn->crtc) { wlr_log(WLR_ERROR, "Connector has no CRTC"); - return -1; + return NULL; } objects[n_objects++] = conn->crtc->id; @@ -1604,50 +1600,63 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, assert(n_objects != 0); - wlr_log(WLR_DEBUG, "Issuing DRM lease with the %d objects", n_objects); + struct wlr_drm_lease *lease = calloc(1, sizeof(*lease)); + if (lease == NULL) { + return NULL; + } + + lease->backend = drm; + wl_signal_init(&lease->events.destroy); + + wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects); int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0, - lessee_id); + &lease->lessee_id); if (lease_fd < 0) { - return lease_fd; + free(lease); + return NULL; } + *lease_fd_ptr = lease_fd; - wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, *lessee_id); + wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, lease->lessee_id); for (size_t i = 0; i < n_outputs; ++i) { struct wlr_drm_connector *conn = get_drm_connector_from_output(outputs[i]); - conn->lessee_id = *lessee_id; - conn->crtc->lessee_id = *lessee_id; + conn->lease = lease; + conn->crtc->lease = lease; } - return lease_fd; + return lease; } -bool wlr_drm_backend_terminate_lease(struct wlr_backend *backend, - uint32_t lessee_id) { - wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lessee_id); +void wlr_drm_lease_terminate(struct wlr_drm_lease *lease) { + struct wlr_drm_backend *drm = lease->backend; - assert(backend); - struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); - - int r = drmModeRevokeLease(drm->fd, lessee_id); - if (r < 0) { - wlr_log_errno(WLR_DEBUG, "Failed to terminate lease"); + wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lease->lessee_id); + int ret = drmModeRevokeLease(drm->fd, lease->lessee_id); + if (ret < 0) { + wlr_log_errno(WLR_ERROR, "Failed to terminate lease"); } + drm_lease_destroy(lease); +} + +void drm_lease_destroy(struct wlr_drm_lease *lease) { + struct wlr_drm_backend *drm = lease->backend; + + wlr_signal_emit_safe(&lease->events.destroy, NULL); + struct wlr_drm_connector *conn; wl_list_for_each(conn, &drm->outputs, link) { - if (conn->lessee_id == lessee_id) { - conn->lessee_id = 0; - /* Will be re-initialized in scan_drm_connectors */ + if (conn->lease == lease) { + conn->lease = NULL; } } for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (drm->crtcs[i].lessee_id == lessee_id) { - drm->crtcs[i].lessee_id = 0; + if (drm->crtcs[i].lease == lease) { + drm->crtcs[i].lease = NULL; } } - return r >= 0; + free(lease); } - diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index e045a72e..d3640afb 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -36,7 +36,7 @@ struct wlr_drm_plane { struct wlr_drm_crtc { uint32_t id; - uint32_t lessee_id; + struct wlr_drm_lease *lease; // Atomic modesetting only uint32_t mode_id; @@ -118,7 +118,7 @@ struct wlr_drm_connector { enum wlr_drm_connector_status status; bool desired_enabled; uint32_t id; - uint32_t lessee_id; + struct wlr_drm_lease *lease; struct wlr_drm_crtc *crtc; uint32_t possible_crtcs; @@ -157,6 +157,7 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn); bool drm_connector_supports_vrr(struct wlr_drm_connector *conn); size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc); +void drm_lease_destroy(struct wlr_drm_lease *lease); struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 0e9f6108..800bc585 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -14,6 +14,20 @@ #include #include +struct wlr_drm_backend; + +struct wlr_drm_lease { + int fd; + uint32_t lessee_id; + struct wlr_drm_backend *backend; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + /** * Creates a DRM backend using the specified GPU file descriptor (typically from * a device node in /dev/dri). @@ -41,18 +55,20 @@ uint32_t wlr_drm_connector_get_id(struct wlr_output *output); int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend); /** - * Leases a given output to the caller. The output must be from the associated - * DRM backend. - * Returns a valid opened DRM FD or -1 on error. + * Leases the given outputs to the caller. The outputs must be from the + * associated DRM backend. + * + * Returns NULL on error. */ -int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs, - uint32_t *lessee_id); +struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs, + size_t n_outputs, int *lease_fd); /** - * Terminates a given lease. The output will be owned again by the backend + * Terminates and destroys a given lease. + * + * The outputs will be owned again by the backend. */ -bool wlr_drm_backend_terminate_lease(struct wlr_backend *backend, - uint32_t lessee_id); +void wlr_drm_lease_terminate(struct wlr_drm_lease *lease); /** * Add mode to the list of available modes diff --git a/include/wlr/types/wlr_drm_lease_v1.h b/include/wlr/types/wlr_drm_lease_v1.h index bf625235..5b4137c5 100644 --- a/include/wlr/types/wlr_drm_lease_v1.h +++ b/include/wlr/types/wlr_drm_lease_v1.h @@ -81,14 +81,13 @@ struct wlr_drm_lease_request_v1 { struct wlr_drm_lease_v1 { struct wl_resource *resource; + struct wlr_drm_lease *drm_lease; struct wlr_drm_lease_device_v1 *device; struct wlr_drm_lease_connector_v1 **connectors; size_t n_connectors; - uint32_t lessee_id; - struct wl_list link; // wlr_drm_lease_device_v1::leases void *data; diff --git a/types/wlr_drm_lease_v1.c b/types/wlr_drm_lease_v1.c index a917930e..eaca8f17 100644 --- a/types/wlr_drm_lease_v1.c +++ b/types/wlr_drm_lease_v1.c @@ -52,13 +52,11 @@ static void drm_lease_v1_destroy(struct wlr_drm_lease_v1 *lease) { return; } - wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->lessee_id); + wlr_log(WLR_DEBUG, "Destroying lease %"PRIu32, lease->drm_lease->lessee_id); wp_drm_lease_v1_send_finished(lease->resource); - struct wlr_drm_lease_device_v1 *device = lease->device; - wlr_drm_backend_terminate_lease(device->backend, lease->lessee_id); - lease->lessee_id = 0; + wlr_drm_lease_terminate(lease->drm_lease); for (size_t i = 0; i < lease->n_connectors; ++i) { lease->connectors[i]->active_lease = NULL; @@ -171,10 +169,10 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( outputs[i] = request->connectors[i]->output; } - int fd = wlr_drm_create_lease(outputs, request->n_connectors, - &lease->lessee_id); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "drm_create_lease failed"); + int fd; + lease->drm_lease = wlr_drm_create_lease(outputs, request->n_connectors, &fd); + if (!lease->drm_lease) { + wlr_log(WLR_ERROR, "wlr_drm_create_lease failed"); wp_drm_lease_v1_send_finished(lease->resource); return NULL; } @@ -183,6 +181,7 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant( sizeof(struct wlr_drm_lease_connector_v1 *)); if (!lease->connectors) { wlr_log(WLR_ERROR, "Failed to allocate lease connectors list"); + close(fd); wp_drm_lease_v1_send_finished(lease->resource); return NULL; } @@ -212,7 +211,7 @@ void wlr_drm_lease_request_v1_reject( void wlr_drm_lease_v1_revoke(struct wlr_drm_lease_v1 *lease) { assert(lease); - wlr_log(WLR_DEBUG, "Revoking lease %"PRIu32, lease->lessee_id); + wlr_log(WLR_DEBUG, "Revoking lease %"PRIu32, lease->drm_lease->lessee_id); drm_lease_v1_destroy(lease); }