diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 5e01eddf..cd5b8ee0 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -22,7 +22,7 @@ struct wlr_drm_backend *get_drm_backend_from_backend( static bool backend_start(struct wlr_backend *backend) { struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); - scan_drm_connectors(drm); + scan_drm_connectors(drm, NULL); return true; } @@ -102,7 +102,7 @@ static void handle_session_active(struct wl_listener *listener, void *data) { if (session->active) { wlr_log(WLR_INFO, "DRM fd resumed"); - scan_drm_connectors(drm); + scan_drm_connectors(drm, NULL); struct wlr_drm_connector *conn; wl_list_for_each(conn, &drm->outputs, link) { @@ -127,13 +127,21 @@ static void handle_session_active(struct wl_listener *listener, void *data) { static void handle_dev_change(struct wl_listener *listener, void *data) { struct wlr_drm_backend *drm = wl_container_of(listener, drm, dev_change); + struct wlr_device_change_event *change = data; if (!drm->session->active) { return; } - wlr_log(WLR_DEBUG, "%s invalidated", drm->name); - scan_drm_connectors(drm); + // TODO: add and handle lease uevents + switch (change->type) { + case WLR_DEVICE_HOTPLUG:; + wlr_log(WLR_DEBUG, "Received hotplug event for %s", drm->name); + scan_drm_connectors(drm, &change->hotplug); + break; + default: + wlr_log(WLR_DEBUG, "Received unknown change event for %s", drm->name); + } } static void handle_dev_remove(struct wl_listener *listener, void *data) { diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 191ad064..3031d09b 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1177,7 +1177,8 @@ static uint32_t get_possible_crtcs(int fd, const drmModeConnector *conn) { static void disconnect_drm_connector(struct wlr_drm_connector *conn); -void scan_drm_connectors(struct wlr_drm_backend *drm) { +void scan_drm_connectors(struct wlr_drm_backend *drm, + struct wlr_device_hotplug_event *event) { /* * This GPU is not really a modesetting device. * It's just being used as a renderer. @@ -1186,7 +1187,12 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { return; } - wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name); + if (event != NULL && event->connector_id != 0) { + wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s", + event->connector_id, drm->name); + } else { + wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name); + } drmModeRes *res = drmModeGetResources(drm->fd); if (!res) { @@ -1203,25 +1209,36 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { struct wlr_drm_connector *new_outputs[res->count_connectors + 1]; for (int i = 0; i < res->count_connectors; ++i) { - drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, - res->connectors[i]); - if (!drm_conn) { - wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); - continue; - } - drmModeEncoder *curr_enc = drmModeGetEncoder(drm->fd, - drm_conn->encoder_id); + uint32_t conn_id = res->connectors[i]; ssize_t index = -1; struct wlr_drm_connector *c, *wlr_conn = NULL; wl_list_for_each(c, &drm->outputs, link) { index++; - if (c->id == drm_conn->connector_id) { + if (c->id == conn_id) { wlr_conn = c; break; } } + // If the hotplug event contains a connector ID, ignore any other + // connector. + if (event != NULL && event->connector_id != 0 && + event->connector_id != conn_id) { + if (wlr_conn != NULL) { + seen[index] = true; + } + continue; + } + + drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, conn_id); + if (!drm_conn) { + wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); + continue; + } + drmModeEncoder *curr_enc = drmModeGetEncoder(drm->fd, + drm_conn->encoder_id); + if (!wlr_conn) { wlr_conn = calloc(1, sizeof(*wlr_conn)); if (!wlr_conn) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 4b2a1f7c..e045a72e 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -147,7 +147,8 @@ struct wlr_drm_backend *get_drm_backend_from_backend( bool check_drm_features(struct wlr_drm_backend *drm); bool init_drm_resources(struct wlr_drm_backend *drm); void finish_drm_resources(struct wlr_drm_backend *drm); -void scan_drm_connectors(struct wlr_drm_backend *state); +void scan_drm_connectors(struct wlr_drm_backend *state, + struct wlr_device_hotplug_event *event); int handle_drm_event(int fd, uint32_t mask, void *data); void destroy_drm_connector(struct wlr_drm_connector *conn); bool drm_connector_commit_state(struct wlr_drm_connector *conn,