aboutsummaryrefslogtreecommitdiff
path: root/backend/drm/drm.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/drm/drm.c')
-rw-r--r--backend/drm/drm.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c
index b9ab7f82..0b624717 100644
--- a/backend/drm/drm.c
+++ b/backend/drm/drm.c
@@ -1,4 +1,4 @@
-#define _POSIX_C_SOURCE 199309L
+#define _POSIX_C_SOURCE 200112L
#include <assert.h>
#include <drm_mode.h>
#include <EGL/egl.h>
@@ -156,6 +156,11 @@ bool init_drm_resources(struct wlr_drm_backend *drm) {
wlr_log(WLR_INFO, "Found %d DRM CRTCs", res->count_crtcs);
drm->num_crtcs = res->count_crtcs;
+ if (drm->num_crtcs == 0) {
+ drmModeFreeResources(res);
+ return true;
+ }
+
drm->crtcs = calloc(drm->num_crtcs, sizeof(drm->crtcs[0]));
if (!drm->crtcs) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
@@ -433,9 +438,9 @@ static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in,
continue;
}
- uint32_t possible[drm->num_type_planes[type]];
- uint32_t crtc[drm->num_crtcs];
- uint32_t crtc_res[drm->num_crtcs];
+ uint32_t possible[drm->num_type_planes[type] + 1];
+ uint32_t crtc[drm->num_crtcs + 1];
+ uint32_t crtc_res[drm->num_crtcs + 1];
for (size_t i = 0; i < drm->num_type_planes[type]; ++i) {
possible[i] = drm->type_planes[type][i].possible_crtcs;
@@ -1078,6 +1083,24 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
wlr_conn->crtc = NULL;
}
+ // This can only happen *after* hotplug, since we haven't read the
+ // connector properties yet
+ if (wlr_conn->props.link_status != 0) {
+ uint64_t link_status;
+ if (!get_drm_prop(drm->fd, wlr_conn->id,
+ wlr_conn->props.link_status, &link_status)) {
+ wlr_log(WLR_ERROR, "Failed to get link status for '%s'",
+ wlr_conn->output.name);
+ continue;
+ }
+
+ if (link_status == DRM_MODE_LINK_STATUS_BAD) {
+ // We need to reload our list of modes and force a modeset
+ wlr_log(WLR_INFO, "Bad link for '%s'", wlr_conn->output.name);
+ drm_connector_cleanup(wlr_conn);
+ }
+ }
+
if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED &&
drm_conn->connection == DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name);
@@ -1160,7 +1183,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
}
}
- bool changed_outputs[wl_list_length(&drm->outputs)];
+ bool changed_outputs[wl_list_length(&drm->outputs) + 1];
memset(changed_outputs, false, sizeof(changed_outputs));
for (size_t i = 0; i < new_outputs_len; ++i) {
struct wlr_drm_connector *conn = new_outputs[i];
@@ -1238,7 +1261,7 @@ static void page_flip_handler(int fd, unsigned seq,
int handle_drm_event(int fd, uint32_t mask, void *data) {
drmEventContext event = {
- .version = DRM_EVENT_CONTEXT_VERSION,
+ .version = 2,
.page_flip_handler = page_flip_handler,
};
@@ -1324,7 +1347,13 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) {
memset(&conn->output.model, 0, sizeof(conn->output.model));
memset(&conn->output.serial, 0, sizeof(conn->output.serial));
- conn->pageflip_pending = false;
+ if (conn->output.idle_frame != NULL) {
+ wl_event_source_remove(conn->output.idle_frame);
+ conn->output.idle_frame = NULL;
+ }
+ conn->output.needs_swap = false;
+ conn->output.frame_pending = false;
+
/* Fallthrough */
case WLR_DRM_CONN_NEEDS_MODESET:
wlr_log(WLR_INFO, "Emitting destruction signal for '%s'",