drmModePlaneResPtr drm_plane_resource;
uint32_t available_crtcs;
+ char **connector_names;
+ int nconnectors;
+
struct lease **leases;
int nleases;
};
[DRM_MODE_CONNECTOR_WRITEBACK] = "Writeback",
};
-static char *drm_create_default_lease_name(struct lm *lm,
- drmModeConnectorPtr connector)
+static char *drm_create_connector_name(drmModeConnectorPtr connector)
{
uint32_t type = connector->connector_type;
uint32_t id = connector->connector_type_id;
id = connector->connector_id;
char *name;
- if (asprintf(&name, "card%d-%s-%d", minor(lm->dev_id),
- connector_type_names[type], id) < 0)
+ if (asprintf(&name, "%s-%d", connector_type_names[type], id) < 0)
+ return NULL;
+
+ return name;
+}
+
+static char *drm_create_default_lease_name(struct lm *lm, int cindex)
+{
+ char *connector_name = lm->connector_names[cindex];
+
+ char *name;
+ if (asprintf(&name, "card%d-%s", minor(lm->dev_id), connector_name) < 0)
return NULL;
return name;
}
}
-static bool lease_add_planes(struct lm *lm, struct lease *lease, int crtc_index)
+static bool drm_find_connector(struct lm *lm, char *name, uint32_t *id)
{
- for (uint32_t i = 0; i < lm->drm_plane_resource->count_planes; i++) {
- uint32_t plane_id = lm->drm_plane_resource->planes[i];
+ int connectors = lm->drm_resource->count_connectors;
+
+ for (int i = 0; i < connectors; i++) {
+ if (strcmp(lm->connector_names[i], name))
+ continue;
+ if (id)
+ *id = lm->drm_resource->connectors[i];
+ return true;
+ }
+ return false;
+}
+
+static void config_get_planes(struct lm *lm,
+ const struct connector_config *config,
+ int *nplanes, uint32_t **planes)
+{
+ if (config && config->planes) {
+ *nplanes = config->nplanes;
+ *planes = config->planes;
+ } else {
+ *nplanes = (int)lm->drm_plane_resource->count_planes;
+ *planes = lm->drm_plane_resource->planes;
+ }
+}
+
+static bool lease_add_planes(struct lm *lm, struct lease *lease,
+ uint32_t crtc_index,
+ const struct connector_config *con_config)
+{
+ int nplanes;
+ uint32_t *planes;
+ uint32_t crtc_mask = (1 << crtc_index);
+
+ /* Only allow shared planes when plane list is explicitly set */
+ bool allow_shared = con_config && con_config->planes;
+
+ config_get_planes(lm, con_config, &nplanes, &planes);
+
+ for (int i = 0; i < nplanes; i++) {
+ uint32_t plane_id = planes[i];
drmModePlanePtr plane = drmModeGetPlane(lm->drm_fd, plane_id);
- assert(plane);
+ if (!plane) {
+ ERROR_LOG(
+ "Unknown plane id %d configured in lease: %s\n",
+ plane_id, lease->base.name);
+ return false;
+ }
- // Exclude planes that can be used with multiple CRTCs for now
- if (plane->possible_crtcs == (1u << crtc_index)) {
- lease->object_ids[lease->nobject_ids++] = plane_id;
+ if (plane->possible_crtcs & crtc_mask) {
+ bool shared_plane = plane->possible_crtcs != crtc_mask;
+ if (allow_shared || !shared_plane)
+ lease->object_ids[lease->nobject_ids++] =
+ plane_id;
}
drmModeFreePlane(plane);
}
goto err;
}
+ int nconnectors =
+ config->nconnectors > 0 ? config->nconnectors : config->ncids;
int nobjects = lm->drm_plane_resource->count_planes +
- config->ncids * DRM_OBJECTS_PER_CONNECTOR;
+ nconnectors * DRM_OBJECTS_PER_CONNECTOR;
lease->object_ids = calloc(nobjects, sizeof(uint32_t));
if (!lease->object_ids) {
goto err;
}
- for (int i = 0; i < config->ncids; i++) {
+ for (int i = 0; i < nconnectors; i++) {
+ uint32_t cid;
+ struct connector_config *con_config = NULL;
+
+ if (config->nconnectors > 0)
+ con_config = &config->connectors[i];
+
+ if (con_config) {
+ char *connector_name = con_config->name;
+ bool optional = con_config->optional;
+
+ bool found =
+ drm_find_connector(lm, connector_name, &cid);
+
+ bool missing_mandatory = !found && !optional;
+ bool missing_optional = !found && optional;
+
+ if (missing_mandatory) {
+ ERROR_LOG("Lease: %s, "
+ "mandatory connector %s not found\n",
+ config->lease_name, connector_name);
+ goto err;
+ } else if (missing_optional) {
+ WARN_LOG("Lease: %s, "
+ "unknown DRM connector: %s\n",
+ config->lease_name, connector_name);
+ continue;
+ }
+ } else {
+ cid = config->connector_ids[i];
+ }
+
drmModeConnectorPtr connector =
- drmModeGetConnector(lm->drm_fd, config->connector_ids[i]);
+ drmModeGetConnector(lm->drm_fd, cid);
if (connector == NULL) {
- ERROR_LOG("Can't find connector id: %d\n",
- config->connector_ids);
+ ERROR_LOG("Can't find connector id: %d\n", cid);
goto err;
}
- uint32_t connector_id = connector->connector_id;
-
int crtc_index = drm_get_crtc_index(lm, connector);
drmModeFreeConnector(connector);
if (crtc_index < 0) {
DEBUG_LOG("No crtc found for connector: %d, lease %s\n",
- connector_id, lease->base.name);
+ cid, lease->base.name);
goto err;
}
- if (!lease_add_planes(lm, lease, crtc_index))
+ if (!lease_add_planes(lm, lease, crtc_index, con_config))
goto err;
uint32_t crtc_id = lm->drm_resource->crtcs[crtc_index];
lease->crtc_id = crtc_id;
lease->object_ids[lease->nobject_ids++] = crtc_id;
- lease->object_ids[lease->nobject_ids++] = connector_id;
+ lease->object_ids[lease->nobject_ids++] = cid;
}
lease->is_granted = false;
lease->lease_fd = -1;
goto err;
}
- drmModeConnectorPtr connector;
- connector = drmModeGetConnector(lm->drm_fd, cid);
def_configs[i].lease_name =
- drm_create_default_lease_name(lm, connector);
-
- if (!def_configs[i].lease_name) {
- DEBUG_LOG(
- "Can't create lease name for connector %d: %s\n",
- cid, strerror(errno));
- goto err;
- }
-
- drmModeFreeConnector(connector);
+ drm_create_default_lease_name(lm, i);
def_configs[i].connector_ids[0] = cid;
def_configs[i].ncids = 1;
goto err;
}
+ /* Enable universal planes so that ALL planes, even primary and cursor
+ * planes can be assigned from lease configurations. */
+ if (drmSetClientCap(lm->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
+ DEBUG_LOG("drmSetClientCap failed\n");
+ goto err;
+ }
+
lm->drm_resource = drmModeGetResources(lm->drm_fd);
if (!lm->drm_resource) {
ERROR_LOG("Invalid DRM device(%s)\n", device);
goto err;
}
+ if (lm->drm_resource->count_connectors <= 0 ||
+ lm->drm_resource->count_crtcs <= 0 ||
+ lm->drm_resource->count_encoders <= 0) {
+ DEBUG_LOG("Insufficient DRM resources on device(%s)\n", device);
+ goto err;
+ }
+
lm->drm_plane_resource = drmModeGetPlaneResources(lm->drm_fd);
if (!lm->drm_plane_resource) {
DEBUG_LOG("drmModeGetPlaneResources failed: %s\n",
lm->dev_id = st.st_rdev;
+ lm->nconnectors = lm->drm_resource->count_connectors;
+ lm->connector_names = calloc(lm->nconnectors, sizeof(char *));
+
+ for (int i = 0; i < lm->nconnectors; i++) {
+ drmModeConnectorPtr connector;
+ uint32_t cid = lm->drm_resource->connectors[i];
+
+ connector = drmModeGetConnector(lm->drm_fd, cid);
+ lm->connector_names[i] = drm_create_connector_name(connector);
+ drmModeFreeConnector(connector);
+
+ if (!lm->connector_names[i]) {
+ DEBUG_LOG("Can't create name for connector %d: %s\n",
+ cid, strerror(errno));
+ goto err;
+ }
+ }
return lm;
err:
lm_destroy(lm);
return NULL;
}
+static struct lm *drm_find_drm_device(const char *device)
+{
+ drmDevicePtr devices[64];
+ int ndevs;
+ struct lm *lm = NULL;
+
+ if (device)
+ return drm_device_get_resources(device);
+
+ ndevs = drmGetDevices2(0, devices, 64);
+
+ for (int i = 0; i < ndevs; i++) {
+ lm = drm_device_get_resources(
+ devices[i]->nodes[DRM_NODE_PRIMARY]);
+ if (lm)
+ break;
+ }
+
+ drmFreeDevices(devices, ndevs);
+
+ return lm;
+}
+
static int lm_create_leases(struct lm *lm, int num_leases,
const struct lease_config *configs)
{
struct lease_config *configs)
{
struct lease_config *default_configs = NULL;
- struct lm *lm = drm_device_get_resources(device);
+ struct lm *lm = drm_find_drm_device(device);
- if (!lm)
+ if (!lm) {
+ ERROR_LOG("No available DRM device found\n");
return NULL;
+ }
- if (configs == NULL) {
+ if (configs == NULL || num_leases == 0) {
num_leases = create_default_lease_configs(lm, &default_configs);
if (num_leases < 0) {
lm_destroy(lm);
}
free(lm->leases);
+
+ for (int i = 0; i < lm->nconnectors; i++)
+ free(lm->connector_names[i]);
+ free(lm->connector_names);
+
drmModeFreeResources(lm->drm_resource);
drmModeFreePlaneResources(lm->drm_plane_resource);
close(lm->drm_fd);