drm-backend: move connector data from struct drm_head to struct drm_connector

This is the first step in order to add support for writeback
connector in Weston. We don't want writeback connectors data
to be stored in 'struct drm_head' objects, as these objects are
used to output content and we should not use writeback connectors
for this purpose.

The writeback connectors will be stored in a new 'struct
drm_writeback', but the connector data is common between
'struct drm_head' and 'struct drm_writeback'.

So move connector data from 'struct drm_head' to 'struct
drm_connector'. This helps to avoid code duplication and makes
the code clearer.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
dev
Leandro Ribeiro 4 years ago committed by Pekka Paalanen
parent bb33f90658
commit e636990de3
  1. 17
      libweston/backend-drm/drm-internal.h
  2. 171
      libweston/backend-drm/drm.c
  3. 60
      libweston/backend-drm/kms.c
  4. 31
      libweston/backend-drm/modes.c

@ -466,16 +466,23 @@ struct drm_plane {
} formats[];
};
struct drm_head {
struct weston_head base;
struct drm_connector {
struct drm_backend *backend;
struct drm_head *head;
drmModeConnector *connector;
drmModeConnector *conn;
uint32_t connector_id;
struct drm_edid edid;
/* Holds the properties for the connector */
struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
struct drm_property_info props[WDRM_CONNECTOR__COUNT];
};
struct drm_head {
struct weston_head base;
struct drm_backend *backend;
struct drm_connector connector;
struct drm_edid edid;
struct backlight *backlight;

@ -213,7 +213,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->connector_id == connector_id)
if (head->connector.connector_id == connector_id)
return head;
}
@ -1362,12 +1362,13 @@ static int
drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
{
int drm_fd = backend->drm.fd;
drmModeConnector *conn = head->connector.conn;
drmModeEncoder *encoder;
drmModeCrtc *crtc;
/* Get the current mode on the crtc that's currently driving
* this connector. */
encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
encoder = drmModeGetEncoder(drm_fd, conn->encoder_id);
if (encoder != NULL) {
head->inherited_crtc_id = encoder->crtc_id;
@ -1426,15 +1427,16 @@ drm_output_init_gamma_size(struct drm_output *output)
}
static uint32_t
drm_head_get_possible_crtcs_mask(struct drm_head *head)
drm_connector_get_possible_crtcs_mask(struct drm_connector *connector)
{
uint32_t possible_crtcs = 0;
drmModeConnector *conn = connector->conn;
drmModeEncoder *encoder;
int i;
for (i = 0; i < head->connector->count_encoders; i++) {
encoder = drmModeGetEncoder(head->backend->drm.fd,
head->connector->encoders[i]);
for (i = 0; i < conn->count_encoders; i++) {
encoder = drmModeGetEncoder(connector->backend->drm.fd,
conn->encoders[i]);
if (!encoder)
continue;
@ -1475,7 +1477,8 @@ drm_output_pick_crtc(struct drm_output *output)
wl_list_for_each(base, &output->base.head_list, output_link) {
head = to_drm_head(base);
possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
possible_crtcs &=
drm_connector_get_possible_crtcs_mask(&head->connector);
crtc_id = head->inherited_crtc_id;
if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
@ -1957,14 +1960,14 @@ drm_head_get_current_protection(struct drm_head *head,
enum wdrm_hdcp_content_type type;
enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
info = &head->connector.props[WDRM_CONNECTOR_CONTENT_PROTECTION];
protection = drm_property_get_value(info, props,
WDRM_CONTENT_PROTECTION__COUNT);
if (protection == WDRM_CONTENT_PROTECTION__COUNT)
return WESTON_HDCP_DISABLE;
info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
info = &head->connector.props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
type = drm_property_get_value(info, props,
WDRM_HDCP_CONTENT_TYPE__COUNT);
@ -1981,7 +1984,7 @@ drm_head_get_current_protection(struct drm_head *head,
&weston_hdcp) == -1) {
weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
protection, type, head->base.name,
head->connector_id);
head->connector.connector_id);
return WESTON_HDCP_DISABLE;
}
@ -1990,62 +1993,87 @@ drm_head_get_current_protection(struct drm_head *head,
/** 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.
* @param connector The drm_connector object to be updated.
* @param conn The connector data to be owned by the drm_connector, must match
* the current drm_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.
* May schedule a heads changed call if this connector is owned by a head
*/
static int
drm_head_assign_connector_info(struct drm_head *head,
drmModeConnector *connector)
drm_connector_assign_connector_info(struct drm_connector *connector,
drmModeConnector *conn)
{
drmModeObjectProperties *props;
assert(connector);
assert(head->connector_id == connector->connector_id);
assert(connector->connector_id == conn->connector_id);
props = drmModeObjectGetProperties(head->backend->drm.fd,
head->connector_id,
props = drmModeObjectGetProperties(connector->backend->drm.fd,
connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!props) {
weston_log("Error: failed to get connector '%s' properties\n",
head->base.name);
weston_log("Error: failed to get connector properties\n");
return -1;
}
if (head->connector)
drmModeFreeConnector(head->connector);
head->connector = connector;
if (connector->conn && connector->conn != conn)
drmModeFreeConnector(connector->conn);
connector->conn = conn;
drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
drm_property_info_populate(head->backend, connector_props,
head->props_conn,
drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
drm_property_info_populate(connector->backend, connector_props,
connector->props,
WDRM_CONNECTOR__COUNT, props);
update_head_from_connector(head, props);
weston_head_set_content_protection_status(&head->base,
drm_head_get_current_protection(head, props));
if (connector->head != NULL) {
update_head_from_connector(connector->head, props);
weston_head_set_content_protection_status(&connector->head->base,
drm_head_get_current_protection(connector->head, props));
}
drmModeFreeObjectProperties(props);
return 0;
}
static int
drm_connector_init(struct drm_backend *b, struct drm_connector *connector,
uint32_t connector_id)
{
connector->backend = b;
connector->connector_id = connector_id;
connector->head = NULL;
connector->conn = drmModeGetConnector(b->drm.fd, connector_id);
if (!connector->conn) {
weston_log("DRM: Could not retrieve connector.\n");
return -1;
}
return 0;
}
static void
drm_connector_fini(struct drm_connector *connector)
{
drmModeFreeConnector(connector->conn);
drm_property_info_free(connector->props, WDRM_CONNECTOR__COUNT);
}
static void
drm_head_log_info(struct drm_head *head, const char *msg)
{
if (head->base.connected) {
weston_log("DRM: head '%s' %s, connector %d is connected, "
"EDID make '%s', model '%s', serial '%s'\n",
head->base.name, msg, head->connector_id,
head->base.name, msg, head->connector.connector_id,
head->base.make, head->base.model,
head->base.serial_number ?: "");
} else {
weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
head->base.name, msg, head->connector_id);
head->base.name, msg, head->connector.connector_id);
}
}
@ -2060,18 +2088,18 @@ drm_head_log_info(struct drm_head *head, const char *msg)
static void
drm_head_update_info(struct drm_head *head)
{
drmModeConnector *connector;
drmModeConnector *conn;
connector = drmModeGetConnector(head->backend->drm.fd,
head->connector_id);
if (!connector) {
conn = drmModeGetConnector(head->backend->drm.fd,
head->connector.connector_id);
if (!conn) {
weston_log("DRM: getting connector info for '%s' failed.\n",
head->base.name);
return;
}
if (drm_head_assign_connector_info(head, connector) < 0)
drmModeFreeConnector(connector);
if (drm_connector_assign_connector_info(&head->connector, conn) < 0)
drmModeFreeConnector(conn);
if (head->base.device_changed)
drm_head_log_info(head, "updated");
@ -2093,39 +2121,42 @@ drm_head_create(struct drm_backend *backend, uint32_t connector_id,
struct udev_device *drm_device)
{
struct drm_head *head;
drmModeConnector *connector;
drmModeConnector *conn;
char *name;
int ret;
head = zalloc(sizeof *head);
if (!head)
return NULL;
connector = drmModeGetConnector(backend->drm.fd, connector_id);
if (!connector)
goto err_alloc;
head->backend = backend;
name = make_connector_name(connector);
ret = drm_connector_init(backend, &head->connector, connector_id);
if (ret < 0)
goto err;
head->connector.head = head;
conn = head->connector.conn;
name = make_connector_name(conn);
if (!name)
goto err_alloc;
goto err_name;
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);
ret = drm_connector_assign_connector_info(&head->connector, conn);
if (ret < 0)
goto err_assign;
if (drm_head_assign_connector_info(head, connector) < 0)
goto err_init;
head->backlight = backlight_init(drm_device, conn->connector_type);
if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
if (conn->connector_type == DRM_MODE_CONNECTOR_LVDS ||
conn->connector_type == DRM_MODE_CONNECTOR_eDP)
weston_head_set_internal(&head->base);
if (drm_head_read_current_setup(head, backend) < 0) {
weston_log("Failed to retrieve current mode from connector %d.\n",
head->connector_id);
head->connector.connector_id);
/* Not fatal. */
}
@ -2134,15 +2165,12 @@ drm_head_create(struct drm_backend *backend, uint32_t connector_id,
return head;
err_init:
err_assign:
weston_head_release(&head->base);
err_alloc:
if (connector)
drmModeFreeConnector(connector);
err_name:
drm_connector_fini(&head->connector);
err:
free(head);
return NULL;
}
@ -2151,8 +2179,7 @@ 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);
drm_connector_fini(&head->connector);
if (head->backlight)
backlight_destroy(head->backlight);
@ -2247,6 +2274,7 @@ drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
drmModeRes *resources;
struct weston_head *base, *next;
struct drm_head *head;
uint32_t connector_id;
int i;
resources = drmModeGetResources(b->drm.fd);
@ -2257,7 +2285,7 @@ drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
/* collect new connectors that have appeared, e.g. MST */
for (i = 0; i < resources->count_connectors; i++) {
uint32_t connector_id = resources->connectors[i];
connector_id = resources->connectors[i];
head = drm_head_find_by_connector(b, connector_id);
if (head) {
@ -2274,11 +2302,11 @@ drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
wl_list_for_each_safe(base, next,
&b->compositor->head_list, compositor_link) {
bool removed = true;
head = to_drm_head(base);
connector_id = head->connector.connector_id;
for (i = 0; i < resources->count_connectors; i++) {
if (resources->connectors[i] == head->connector_id) {
if (resources->connectors[i] == connector_id) {
removed = false;
break;
}
@ -2288,7 +2316,7 @@ drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
continue;
weston_log("DRM: head '%s' (connector %d) disappeared.\n",
head->base.name, head->connector_id);
head->base.name, connector_id);
drm_head_destroy(head);
}
@ -2296,16 +2324,17 @@ drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
}
static enum wdrm_connector_property
drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
drm_connector_find_property_by_id(struct drm_connector *connector,
uint32_t property_id)
{
int i;
enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
if (!head || !property_id)
if (!connector || !property_id)
return WDRM_CONNECTOR__COUNT;
for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
if (head->props_conn[i].prop_id == property_id) {
if (connector->props[i].prop_id == property_id) {
prop = (enum wdrm_connector_property) i;
break;
}
@ -2328,7 +2357,7 @@ drm_backend_update_conn_props(struct drm_backend *b,
return;
}
conn_prop = drm_head_find_property_by_id(head, property_id);
conn_prop = drm_connector_find_property_by_id(&head->connector, property_id);
if (conn_prop >= WDRM_CONNECTOR__COUNT)
return;

@ -676,7 +676,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
wl_list_for_each(head, &output->base.head_list, base.output_link) {
assert(n_conn < MAX_CLONED_CONNECTORS);
connectors[n_conn++] = head->connector_id;
connectors[n_conn++] = head->connector.connector_id;
}
/* If disable_planes is set then assign_planes() wasn't
@ -772,12 +772,12 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (state->dpms != output->state_cur->dpms) {
wl_list_for_each(head, &output->base.head_list, base.output_link) {
dpms_prop = &head->props_conn[WDRM_CONNECTOR_DPMS];
dpms_prop = &head->connector.props[WDRM_CONNECTOR_DPMS];
if (dpms_prop->prop_id == 0)
continue;
ret = drmModeConnectorSetProperty(backend->drm.fd,
head->connector_id,
head->connector.connector_id,
dpms_prop->prop_id,
state->dpms);
if (ret) {
@ -817,19 +817,19 @@ crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
}
static int
connector_add_prop(drmModeAtomicReq *req, struct drm_head *head,
connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
enum wdrm_connector_property prop, uint64_t val)
{
struct drm_property_info *info = &head->props_conn[prop];
struct drm_property_info *info = &connector->props[prop];
uint32_t connector_id = connector->connector_id;
int ret;
if (info->prop_id == 0)
return -1;
ret = drmModeAtomicAddProperty(req, head->connector_id,
info->prop_id, val);
drm_debug(head->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) head->connector_id,
ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) connector_id,
(unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val);
return (ret <= 0) ? -1 : 0;
@ -855,10 +855,10 @@ plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
}
static bool
drm_head_has_prop(struct drm_head *head,
drm_connector_has_prop(struct drm_connector *connector,
enum wdrm_connector_property prop)
{
if (head && head->props_conn[prop].prop_id != 0)
if (connector->props[prop].prop_id != 0)
return true;
return false;
@ -894,7 +894,7 @@ get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
}
static void
drm_head_set_hdcp_property(struct drm_head *head,
drm_connector_set_hdcp_property(struct drm_connector *connector,
enum weston_hdcp_protection protection,
drmModeAtomicReq *req)
{
@ -903,11 +903,12 @@ drm_head_set_hdcp_property(struct drm_head *head,
enum wdrm_hdcp_content_type drm_cp_type;
struct drm_property_enum_info *enum_info;
uint64_t prop_val;
struct drm_property_info *props = connector->props;
get_drm_protection_from_weston(protection, &drm_protection,
&drm_cp_type);
if (!drm_head_has_prop(head, WDRM_CONNECTOR_CONTENT_PROTECTION))
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_CONTENT_PROTECTION))
return;
/*
@ -915,23 +916,23 @@ drm_head_set_hdcp_property(struct drm_head *head,
* HDCP2.2, therefore, type-1 cannot be supported. The type-0 content
* still can be supported if the content-protection property is exposed.
*/
if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE) &&
drm_cp_type != WDRM_HDCP_CONTENT_TYPE0)
return;
enum_info = head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
enum_info = props[WDRM_CONNECTOR_CONTENT_PROTECTION].enum_values;
prop_val = enum_info[drm_protection].value;
ret = connector_add_prop(req, head, WDRM_CONNECTOR_CONTENT_PROTECTION,
prop_val);
ret = connector_add_prop(req, connector,
WDRM_CONNECTOR_CONTENT_PROTECTION, prop_val);
assert(ret == 0);
if (!drm_head_has_prop(head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_HDCP_CONTENT_TYPE))
return;
enum_info = head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
enum_info = props[WDRM_CONNECTOR_HDCP_CONTENT_TYPE].enum_values;
prop_val = enum_info[drm_cp_type].value;
ret = connector_add_prop(req, head, WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
prop_val);
ret = connector_add_prop(req, connector,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE, prop_val);
assert(ret == 0);
}
@ -969,7 +970,8 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
/* No need for the DPMS property, since it is implicit in
* routing and CRTC activity. */
wl_list_for_each(head, &output->base.head_list, base.output_link) {
ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID,
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID,
crtc->crtc_id);
}
} else {
@ -979,11 +981,13 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
/* No need for the DPMS property, since it is implicit in
* routing and CRTC activity. */
wl_list_for_each(head, &output->base.head_list, base.output_link)
ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, 0);
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
}
wl_list_for_each(head, &output->base.head_list, base.output_link)
drm_head_set_hdcp_property(head, state->protection, req);
drm_connector_set_hdcp_property(&head->connector,
state->protection, req);
if (ret != 0) {
weston_log("couldn't set atomic CRTC/connector state\n");
@ -1081,6 +1085,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
struct weston_head *head_base;
struct drm_head *head;
struct drm_crtc *crtc;
uint32_t connector_id;
int err;
drm_debug(b, "\t\t[atomic] previous state invalid; "
@ -1097,15 +1102,16 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
continue;
head = to_drm_head(head_base);
connector_id = head->connector.connector_id;
drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
head_base->name);
info = &head->props_conn[WDRM_CONNECTOR_CRTC_ID];
err = drmModeAtomicAddProperty(req, head->connector_id,
info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
err = drmModeAtomicAddProperty(req, connector_id,
info->prop_id, 0);
drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
(unsigned long) head->connector_id,
(unsigned long) connector_id,
(unsigned long) info->prop_id,
info->name);
if (err <= 0)

@ -120,19 +120,19 @@ drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
}
static bool
check_non_desktop(struct drm_head *head, drmModeObjectPropertiesPtr props)
check_non_desktop(struct drm_connector *connector, drmModeObjectPropertiesPtr props)
{
struct drm_property_info *non_desktop_info =
&head->props_conn[WDRM_CONNECTOR_NON_DESKTOP];
&connector->props[WDRM_CONNECTOR_NON_DESKTOP];
return drm_property_get_value(non_desktop_info, props, 0);
}
static uint32_t
get_panel_orientation(struct drm_head *head, drmModeObjectPropertiesPtr props)
get_panel_orientation(struct drm_connector *connector, drmModeObjectPropertiesPtr props)
{
struct drm_property_info *orientation =
&head->props_conn[WDRM_CONNECTOR_PANEL_ORIENTATION];
&connector->props[WDRM_CONNECTOR_PANEL_ORIENTATION];
uint64_t kms_val =
drm_property_get_value(orientation, props,
WDRM_PANEL_ORIENTATION_NORMAL);
@ -322,7 +322,8 @@ find_and_parse_output_edid(struct drm_head *head,
int rc;
blob_id =
drm_property_get_value(&head->props_conn[WDRM_CONNECTOR_EDID],
drm_property_get_value(
&head->connector.props[WDRM_CONNECTOR_EDID],
props, 0);
if (!blob_id)
return;
@ -509,6 +510,8 @@ void
update_head_from_connector(struct drm_head *head,
drmModeObjectProperties *props)
{
struct drm_connector *connector = &head->connector;
drmModeConnector *conn = connector->conn;
const char *make = "unknown";
const char *model = "unknown";
const char *serial_number = "unknown";
@ -516,19 +519,18 @@ update_head_from_connector(struct drm_head *head,
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_non_desktop(&head->base,
check_non_desktop(head, props));
check_non_desktop(connector, props));
weston_head_set_subpixel(&head->base,
drm_subpixel_to_wayland(head->connector->subpixel));
drm_subpixel_to_wayland(conn->subpixel));
weston_head_set_physical_size(&head->base, head->connector->mmWidth,
head->connector->mmHeight);
weston_head_set_physical_size(&head->base, conn->mmWidth, conn->mmHeight);
weston_head_set_transform(&head->base,
get_panel_orientation(head, props));
get_panel_orientation(connector, props));
/* Unknown connection status is assumed disconnected. */
weston_head_set_connection_status(&head->base,
head->connector->connection == DRM_MODE_CONNECTED);
conn->connection == DRM_MODE_CONNECTED);
}
/**
@ -757,6 +759,7 @@ drm_output_update_modelist_from_heads(struct drm_output *output)
struct drm_backend *backend = to_drm_backend(output->base.compositor);
struct weston_head *head_base;
struct drm_head *head;
drmModeConnector *conn;
int i;
int ret;
@ -766,9 +769,9 @@ drm_output_update_modelist_from_heads(struct drm_output *output)
wl_list_for_each(head_base, &output->base.head_list, output_link) {
head = to_drm_head(head_base);
for (i = 0; i < head->connector->count_modes; i++) {
ret = drm_output_try_add_mode(output,
&head->connector->modes[i]);
conn = head->connector.conn;
for (i = 0; i < conn->count_modes; i++) {
ret = drm_output_try_add_mode(output, &conn->modes[i]);
if (ret < 0)
return -1;
}

Loading…
Cancel
Save