compositor-drm: move connector fields into drm_head
authorPekka Paalanen <pekka.paalanen@collabora.co.uk>
Thu, 31 Aug 2017 13:18:48 +0000 (16:18 +0300)
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>
Wed, 18 Apr 2018 08:44:30 +0000 (11:44 +0300)
Move the connector related fields from drm_output to the drm_head. A
drm_head represents a connector for now.

The code in drm_head_create() to update connector data, monitor
information, etc. is moved into a new function. This will be useful when
DRM-backend starts creating heads for all connectors regardless of their
connection status and will need to update them on hotplug events.

While incurring the churn to move several fields into struct drm_head,
also refactor out drm_head_assign_connector_info(). This function is
needed later when drm_heads will exist regardless of connected status,
as every hotplug event will need to update the state of all connectors.
At that point we will also start handling connector changes that do not
go through an intermediate disconnected state. This refactoring is
trivial enough to be in this patch to reduce the total amount of changes
to be reviewed.

v6:
- adapt to the new places of updating unused_connectors
- free connector in create_output_for_connector() error path

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Acked-by: Derek Foreman <derekf@osg.samsung.com>
libweston/compositor-drm.c

index 4aca6ac..701a40c 100644 (file)
@@ -408,20 +408,22 @@ struct drm_head {
 
        struct drm_output *output; /* XXX: temporary */
 
+       drmModeConnector *connector;
+       uint32_t connector_id;
+       struct drm_edid edid;
+
+       /* Holds the properties for the connector */
+       struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
+
        struct backlight *backlight;
 };
 
 struct drm_output {
        struct weston_output base;
-       drmModeConnector *connector;
 
        uint32_t crtc_id; /* object ID to pass to DRM functions */
        int pipe; /* index of CRTC in resource array / bitmasks */
-       uint32_t connector_id;
-       struct drm_edid edid;
 
-       /* Holds the properties for the connector */
-       struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
        /* Holds the properties for the CRTC */
        struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
 
@@ -812,7 +814,7 @@ drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
        wl_list_for_each(base,
                         &backend->compositor->head_list, compositor_link) {
                head = to_drm_head(base);
-               if (head->output && head->output->connector_id == connector_id)
+               if (head->connector_id == connector_id)
                        return head;
        }
 
@@ -1815,10 +1817,11 @@ static int
 drm_output_apply_state_legacy(struct drm_output_state *state)
 {
        struct drm_output *output = state->output;
+       struct drm_head *head = to_drm_head(weston_output_get_first_head(&output->base));
        struct drm_backend *backend = to_drm_backend(output->base.compositor);
        struct drm_plane *scanout_plane = output->scanout_plane;
        struct drm_property_info *dpms_prop =
-               &output->props_conn[WDRM_CONNECTOR_DPMS];
+               &head->props_conn[WDRM_CONNECTOR_DPMS];
        struct drm_plane_state *scanout_state;
        struct drm_plane_state *ps;
        struct drm_plane *p;
@@ -1861,7 +1864,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
                }
 
                ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
-                                    &output->connector_id, 0, NULL);
+                                    &head->connector_id, 0, NULL);
                if (ret)
                        weston_log("drmModeSetCrtc failed disabling: %m\n");
 
@@ -1896,7 +1899,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
                ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
                                     scanout_state->fb->fb_id,
                                     0, 0,
-                                    &output->connector_id, 1,
+                                    &head->connector_id, 1,
                                     &mode->mode_info);
                if (ret) {
                        weston_log("set mode failed: %m\n");
@@ -1969,7 +1972,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
 
        if (dpms_prop->prop_id && state->dpms != output->state_cur->dpms) {
                ret = drmModeConnectorSetProperty(backend->drm.fd,
-                                                 output->connector_id,
+                                                 head->connector_id,
                                                  dpms_prop->prop_id,
                                                  state->dpms);
                if (ret) {
@@ -2005,16 +2008,16 @@ crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
 }
 
 static int
-connector_add_prop(drmModeAtomicReq *req, struct drm_output *output,
+connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
                   enum wdrm_connector_property prop, uint64_t val)
 {
-       struct drm_property_info *info = &output->props_conn[prop];
+       struct drm_property_info *info = &head->props_conn[prop];
        int ret;
 
        if (info->prop_id == 0)
                return -1;
 
-       ret = drmModeAtomicAddProperty(req, output->connector_id,
+       ret = drmModeAtomicAddProperty(req, head->connector_id,
                                       info->prop_id, val);
        return (ret <= 0) ? -1 : 0;
 }
@@ -2058,6 +2061,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
                              uint32_t *flags)
 {
        struct drm_output *output = state->output;
+       struct drm_head *head = to_drm_head(weston_output_get_first_head(&output->base));
        struct drm_backend *backend = to_drm_backend(output->base.compositor);
        struct drm_plane_state *plane_state;
        struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
@@ -2074,13 +2078,12 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
                ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
                                     current_mode->blob_id);
                ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
-               ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
+               ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
                                          output->crtc_id);
        } else {
                ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
                ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
-               ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
-                                         0);
+               ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
        }
 
        if (ret != 0) {
@@ -4296,8 +4299,7 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
 
 /** Parse monitor make, model and serial from EDID
  *
- * \param b The backend instance.
- * \param output The output whose \c drm_edid to fill in.
+ * \param head The head whose \c drm_edid to fill in.
  * \param props The DRM connector properties to get the EDID from.
  * \param make[out] The monitor make (PNP ID).
  * \param model[out] The monitor model (name).
@@ -4306,10 +4308,10 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
  * Each of \c *make, \c *model and \c *serial_number are set only if the
  * information is found in the EDID. The pointers they are set to must not
  * be free()'d explicitly, instead they get implicitly freed when the
- * \c drm_output is destroyed.
+ * \c drm_head is destroyed.
  */
 static void
-find_and_parse_output_edid(struct drm_backend *b, struct drm_output *output,
+find_and_parse_output_edid(struct drm_head *head,
                           drmModeObjectPropertiesPtr props,
                           const char **make,
                           const char **model,
@@ -4320,29 +4322,29 @@ find_and_parse_output_edid(struct drm_backend *b, struct drm_output *output,
        int rc;
 
        blob_id =
-               drm_property_get_value(&output->props_conn[WDRM_CONNECTOR_EDID],
+               drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
                                       props, 0);
        if (!blob_id)
                return;
 
-       edid_blob = drmModeGetPropertyBlob(b->drm.fd, blob_id);
+       edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id);
        if (!edid_blob)
                return;
 
-       rc = edid_parse(&output->edid,
+       rc = edid_parse(&head->edid,
                        edid_blob->data,
                        edid_blob->length);
        if (!rc) {
                weston_log("EDID data '%s', '%s', '%s'\n",
-                          output->edid.pnp_id,
-                          output->edid.monitor_name,
-                          output->edid.serial_number);
-               if (output->edid.pnp_id[0] != '\0')
-                       *make = output->edid.pnp_id;
-               if (output->edid.monitor_name[0] != '\0')
-                       *model = output->edid.monitor_name;
-               if (output->edid.serial_number[0] != '\0')
-                       *serial_number = output->edid.serial_number;
+                          head->edid.pnp_id,
+                          head->edid.monitor_name,
+                          head->edid.serial_number);
+               if (head->edid.pnp_id[0] != '\0')
+                       *make = head->edid.pnp_id;
+               if (head->edid.monitor_name[0] != '\0')
+                       *model = head->edid.monitor_name;
+               if (head->edid.serial_number[0] != '\0')
+                       *serial_number = head->edid.serial_number;
        }
        drmModeFreePropertyBlob(edid_blob);
 }
@@ -4569,11 +4571,12 @@ drm_output_set_mode(struct weston_output *base,
 {
        struct drm_output *output = to_drm_output(base);
        struct drm_backend *b = to_drm_backend(base->compositor);
+       struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
 
        struct drm_mode *current;
        drmModeModeInfo crtc_mode;
 
-       if (connector_get_current_mode(output->connector, b->drm.fd, &crtc_mode) < 0)
+       if (connector_get_current_mode(head->connector, b->drm.fd, &crtc_mode) < 0)
                return -1;
 
        current = drm_output_choose_initial_mode(b, output, mode, modeline, &crtc_mode);
@@ -4788,11 +4791,11 @@ drm_output_enable(struct weston_output *base)
                                      &output->scanout_plane->base,
                                      &b->compositor->primary_plane);
 
-       wl_array_remove_uint32(&b->unused_connectors, output->connector_id);
+       wl_array_remove_uint32(&b->unused_connectors, head->connector_id);
        wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
 
        weston_log("Output %s, (connector %d, crtc %d)\n",
-                  output->base.name, output->connector_id, output->crtc_id);
+                  output->base.name, head->connector_id, output->crtc_id);
        wl_list_for_each(m, &output->base.mode_list, link)
                weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
                                    m->width, m->height, m->refresh / 1000.0,
@@ -4800,7 +4803,7 @@ drm_output_enable(struct weston_output *base)
                                    ", preferred" : "",
                                    m->flags & WL_OUTPUT_MODE_CURRENT ?
                                    ", current" : "",
-                                   output->connector->count_modes == 0 ?
+                                   head->connector->count_modes == 0 ?
                                    ", built-in" : "");
 
        return 0;
@@ -4813,6 +4816,7 @@ static void
 drm_output_deinit(struct weston_output *base)
 {
        struct drm_output *output = to_drm_output(base);
+       struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
        struct drm_backend *b = to_drm_backend(base->compositor);
        uint32_t *unused;
 
@@ -4838,7 +4842,7 @@ drm_output_deinit(struct weston_output *base)
        }
 
        unused = wl_array_add(&b->unused_connectors, sizeof(*unused));
-       *unused = output->connector_id;
+       *unused = head->connector_id;
        unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
        *unused = output->crtc_id;
 
@@ -4875,9 +4879,6 @@ drm_output_destroy(struct weston_output *base)
 
        drm_output_fini_crtc(output);
 
-       drm_property_info_free(output->props_conn, WDRM_CONNECTOR__COUNT);
-       drmModeFreeConnector(output->connector);
-
        assert(!output->state_last);
        drm_output_state_free(output->state_cur);
 
@@ -4967,6 +4968,62 @@ drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
        }
 }
 
+/** Replace connector data and monitor information
+ *
+ * @param head The head to update.
+ * @param connector The connector data to be owned by the head, must match
+ * the head's connector ID.
+ * @return 0 on success, -1 on failure.
+ *
+ * Takes ownership of @c connector on success, not on failure.
+ *
+ * May schedule a heads changed call.
+ */
+static int
+drm_head_assign_connector_info(struct drm_head *head,
+                              drmModeConnector *connector)
+{
+       drmModeObjectProperties *props;
+       const char *make = "unknown";
+       const char *model = "unknown";
+       const char *serial_number = "unknown";
+
+       assert(connector);
+       assert(head->connector_id == connector->connector_id);
+
+       props = drmModeObjectGetProperties(head->backend->drm.fd,
+                                          head->connector_id,
+                                          DRM_MODE_OBJECT_CONNECTOR);
+       if (!props) {
+               weston_log("Error: failed to get connector '%s' properties\n",
+                          head->base.name);
+               return -1;
+       }
+
+       if (head->connector)
+               drmModeFreeConnector(head->connector);
+       head->connector = connector;
+
+       drm_property_info_populate(head->backend, connector_props,
+                                  head->props_conn,
+                                  WDRM_CONNECTOR__COUNT, props);
+       find_and_parse_output_edid(head, props, &make, &model, &serial_number);
+       weston_head_set_monitor_strings(&head->base, make, model, serial_number);
+       weston_head_set_subpixel(&head->base,
+               drm_subpixel_to_wayland(head->connector->subpixel));
+
+       weston_head_set_physical_size(&head->base, head->connector->mmWidth,
+                                     head->connector->mmHeight);
+
+       drmModeFreeObjectProperties(props);
+
+       /* Unknown connection status is assumed disconnected. */
+       weston_head_set_connection_status(&head->base,
+                       head->connector->connection == DRM_MODE_CONNECTED);
+
+       return 0;
+}
+
 /**
  * Create a Weston head for a connector
  *
@@ -5001,23 +5058,29 @@ drm_head_create(struct drm_backend *backend, uint32_t connector_id,
        weston_head_init(&head->base, name);
        free(name);
 
+       head->connector_id = connector_id;
        head->backend = backend;
 
        head->backlight = backlight_init(drm_device, connector->connector_type);
 
-       /* Unknown connection status is assumed disconnected. */
-       weston_head_set_connection_status(&head->base,
-                               connector->connection == DRM_MODE_CONNECTED);
+       if (drm_head_assign_connector_info(head, connector) < 0)
+               goto err_init;
+
+       if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+           head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               weston_head_set_internal(&head->base);
 
        weston_compositor_add_head(backend->compositor, &head->base);
-       drmModeFreeConnector(connector);
 
        weston_log("DRM: found head '%s', connector %d %s.\n",
-                  head->base.name, connector_id,
+                  head->base.name, head->connector_id,
                   head->base.connected ? "connected" : "disconnected");
 
        return head;
 
+err_init:
+       weston_head_release(&head->base);
+
 err_alloc:
        if (connector)
                drmModeFreeConnector(connector);
@@ -5032,6 +5095,9 @@ drm_head_destroy(struct drm_head *head)
 {
        weston_head_release(&head->base);
 
+       drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
+       drmModeFreeConnector(head->connector);
+
        if (head->backlight)
                backlight_destroy(head->backlight);
 
@@ -5059,31 +5125,21 @@ create_output_for_connector(struct drm_backend *b,
 {
        struct drm_output *output;
        struct drm_head *head;
-       drmModeObjectPropertiesPtr props;
        struct drm_mode *drm_mode;
-       char *name;
-       const char *make = "unknown";
-       const char *model = "unknown";
-       const char *serial_number = "unknown";
        int i;
 
        output = zalloc(sizeof *output);
        if (output == NULL)
                goto err_init;
 
-       output->connector = connector;
-       output->connector_id = connector->connector_id;
-
-       name = make_connector_name(connector);
-       weston_output_init(&output->base, b->compositor, name);
-       free(name);
-
        /* XXX: temporary */
        head = drm_head_create(b, connector->connector_id, drm_device);
        if (!head)
                abort();
        head->output = output;
 
+       weston_output_init(&output->base, b->compositor, head->base.name);
+
        output->base.enable = drm_output_enable;
        output->base.destroy = drm_output_destroy;
        output->base.disable = drm_output_disable;
@@ -5095,36 +5151,13 @@ create_output_for_connector(struct drm_backend *b,
        if (drm_output_init_crtc(output, resources, connector) < 0)
                goto err_output;
 
-       props = drmModeObjectGetProperties(b->drm.fd, connector->connector_id,
-                                          DRM_MODE_OBJECT_CONNECTOR);
-       if (!props) {
-               weston_log("failed to get connector properties\n");
-               goto err_output;
-       }
-       drm_property_info_populate(b, connector_props, output->props_conn,
-                                  WDRM_CONNECTOR__COUNT, props);
-       find_and_parse_output_edid(b, output, props,
-                                  &make, &model, &serial_number);
-       weston_head_set_monitor_strings(&head->base, make, model, serial_number);
-       weston_head_set_subpixel(&head->base,
-               drm_subpixel_to_wayland(output->connector->subpixel));
-
-       drmModeFreeObjectProperties(props);
-
-       if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
-           output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-               weston_head_set_internal(&head->base);
-
        if (drm_output_init_gamma_size(output) < 0)
                goto err_output;
 
-       weston_head_set_physical_size(&head->base, output->connector->mmWidth,
-                                     output->connector->mmHeight);
-
        output->state_cur = drm_output_state_alloc(output, NULL);
 
-       for (i = 0; i < output->connector->count_modes; i++) {
-               drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
+       for (i = 0; i < head->connector->count_modes; i++) {
+               drm_mode = drm_output_add_mode(output, &head->connector->modes[i]);
                if (!drm_mode) {
                        weston_log("failed to add mode\n");
                        goto err_output;
@@ -5133,13 +5166,14 @@ create_output_for_connector(struct drm_backend *b,
 
        weston_compositor_add_pending_output(&output->base, b->compositor);
 
+       /* drm_head_create() made its own connector */
+       drmModeFreeConnector(connector);
+
        return 0;
 
 err_output:
        drm_head_destroy(head);
        drm_output_destroy(&output->base);
-       return -1;
-       /* no fallthrough! */
 
 err_init:
        drmModeFreeConnector(connector);
@@ -5250,7 +5284,7 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
                        continue;
 
                for (i = 0; i < resources->count_connectors; i++) {
-                       if (connected[i] == head->output->connector_id) {
+                       if (connected[i] == head->connector_id) {
                                disconnected = false;
                                break;
                        }
@@ -5259,7 +5293,7 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
                if (!disconnected)
                        continue;
 
-               weston_log("connector %d disconnected\n", head->output->connector_id);
+               weston_log("connector %d disconnected\n", head->connector_id);
                drm_output_destroy(&head->output->base);
        }