|
@@ -683,7 +683,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
|
|
drm_modeset_lock_init(&crtc->mutex);
|
|
drm_modeset_lock_init(&crtc->mutex);
|
|
|
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
|
|
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- goto out;
|
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
crtc->base.properties = &crtc->properties;
|
|
crtc->base.properties = &crtc->properties;
|
|
|
|
|
|
|
@@ -697,9 +697,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
|
|
if (cursor)
|
|
if (cursor)
|
|
|
cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
|
|
cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
|
|
|
|
|
|
|
|
- out:
|
|
|
|
|
-
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_crtc_init_with_planes);
|
|
EXPORT_SYMBOL(drm_crtc_init_with_planes);
|
|
|
|
|
|
|
@@ -723,6 +721,12 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
|
|
|
drm_mode_object_put(dev, &crtc->base);
|
|
drm_mode_object_put(dev, &crtc->base);
|
|
|
list_del(&crtc->head);
|
|
list_del(&crtc->head);
|
|
|
dev->mode_config.num_crtc--;
|
|
dev->mode_config.num_crtc--;
|
|
|
|
|
+
|
|
|
|
|
+ WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
|
|
|
|
|
+ if (crtc->state && crtc->funcs->atomic_destroy_state)
|
|
|
|
|
+ crtc->funcs->atomic_destroy_state(crtc, crtc->state);
|
|
|
|
|
+
|
|
|
|
|
+ memset(crtc, 0, sizeof(*crtc));
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_crtc_cleanup);
|
|
EXPORT_SYMBOL(drm_crtc_cleanup);
|
|
|
|
|
|
|
@@ -766,7 +770,6 @@ static void drm_mode_remove(struct drm_connector *connector,
|
|
|
/**
|
|
/**
|
|
|
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
|
|
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
|
|
|
* @connector: connector to quwery
|
|
* @connector: connector to quwery
|
|
|
- * @mode: returned mode
|
|
|
|
|
*
|
|
*
|
|
|
* The kernel supports per-connector configration of its consoles through
|
|
* The kernel supports per-connector configration of its consoles through
|
|
|
* use of the video= parameter. This function parses that option and
|
|
* use of the video= parameter. This function parses that option and
|
|
@@ -870,6 +873,8 @@ int drm_connector_init(struct drm_device *dev,
|
|
|
|
|
|
|
|
drm_connector_get_cmdline_mode(connector);
|
|
drm_connector_get_cmdline_mode(connector);
|
|
|
|
|
|
|
|
|
|
+ /* We should add connectors at the end to avoid upsetting the connector
|
|
|
|
|
+ * index too much. */
|
|
|
list_add_tail(&connector->head, &dev->mode_config.connector_list);
|
|
list_add_tail(&connector->head, &dev->mode_config.connector_list);
|
|
|
dev->mode_config.num_connector++;
|
|
dev->mode_config.num_connector++;
|
|
|
|
|
|
|
@@ -905,6 +910,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_device *dev = connector->dev;
|
|
|
struct drm_display_mode *mode, *t;
|
|
struct drm_display_mode *mode, *t;
|
|
|
|
|
|
|
|
|
|
+ if (connector->tile_group) {
|
|
|
|
|
+ drm_mode_put_tile_group(dev, connector->tile_group);
|
|
|
|
|
+ connector->tile_group = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
|
|
list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
|
|
|
drm_mode_remove(connector, mode);
|
|
drm_mode_remove(connector, mode);
|
|
|
|
|
|
|
@@ -919,6 +929,13 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
|
|
connector->name = NULL;
|
|
connector->name = NULL;
|
|
|
list_del(&connector->head);
|
|
list_del(&connector->head);
|
|
|
dev->mode_config.num_connector--;
|
|
dev->mode_config.num_connector--;
|
|
|
|
|
+
|
|
|
|
|
+ WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
|
|
|
|
|
+ if (connector->state && connector->funcs->atomic_destroy_state)
|
|
|
|
|
+ connector->funcs->atomic_destroy_state(connector,
|
|
|
|
|
+ connector->state);
|
|
|
|
|
+
|
|
|
|
|
+ memset(connector, 0, sizeof(*connector));
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_connector_cleanup);
|
|
EXPORT_SYMBOL(drm_connector_cleanup);
|
|
|
|
|
|
|
@@ -933,6 +950,9 @@ unsigned int drm_connector_index(struct drm_connector *connector)
|
|
|
{
|
|
{
|
|
|
unsigned int index = 0;
|
|
unsigned int index = 0;
|
|
|
struct drm_connector *tmp;
|
|
struct drm_connector *tmp;
|
|
|
|
|
+ struct drm_mode_config *config = &connector->dev->mode_config;
|
|
|
|
|
+
|
|
|
|
|
+ WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
|
|
|
|
|
|
|
|
list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
|
|
list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
|
|
|
if (tmp == connector)
|
|
if (tmp == connector)
|
|
@@ -1057,6 +1077,8 @@ void drm_bridge_cleanup(struct drm_bridge *bridge)
|
|
|
list_del(&bridge->head);
|
|
list_del(&bridge->head);
|
|
|
dev->mode_config.num_bridge--;
|
|
dev->mode_config.num_bridge--;
|
|
|
drm_modeset_unlock_all(dev);
|
|
drm_modeset_unlock_all(dev);
|
|
|
|
|
+
|
|
|
|
|
+ memset(bridge, 0, sizeof(*bridge));
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_bridge_cleanup);
|
|
EXPORT_SYMBOL(drm_bridge_cleanup);
|
|
|
|
|
|
|
@@ -1123,10 +1145,11 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
|
|
|
drm_modeset_lock_all(dev);
|
|
drm_modeset_lock_all(dev);
|
|
|
drm_mode_object_put(dev, &encoder->base);
|
|
drm_mode_object_put(dev, &encoder->base);
|
|
|
kfree(encoder->name);
|
|
kfree(encoder->name);
|
|
|
- encoder->name = NULL;
|
|
|
|
|
list_del(&encoder->head);
|
|
list_del(&encoder->head);
|
|
|
dev->mode_config.num_encoder--;
|
|
dev->mode_config.num_encoder--;
|
|
|
drm_modeset_unlock_all(dev);
|
|
drm_modeset_unlock_all(dev);
|
|
|
|
|
+
|
|
|
|
|
+ memset(encoder, 0, sizeof(*encoder));
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_encoder_cleanup);
|
|
EXPORT_SYMBOL(drm_encoder_cleanup);
|
|
|
|
|
|
|
@@ -1153,11 +1176,11 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|
|
{
|
|
{
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
-
|
|
|
|
|
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
|
|
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- goto out;
|
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
+
|
|
|
|
|
+ drm_modeset_lock_init(&plane->mutex);
|
|
|
|
|
|
|
|
plane->base.properties = &plane->properties;
|
|
plane->base.properties = &plane->properties;
|
|
|
plane->dev = dev;
|
|
plane->dev = dev;
|
|
@@ -1167,8 +1190,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|
|
if (!plane->format_types) {
|
|
if (!plane->format_types) {
|
|
|
DRM_DEBUG_KMS("out of memory when allocating plane\n");
|
|
DRM_DEBUG_KMS("out of memory when allocating plane\n");
|
|
|
drm_mode_object_put(dev, &plane->base);
|
|
drm_mode_object_put(dev, &plane->base);
|
|
|
- ret = -ENOMEM;
|
|
|
|
|
- goto out;
|
|
|
|
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
|
|
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
|
|
@@ -1185,10 +1207,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|
|
dev->mode_config.plane_type_property,
|
|
dev->mode_config.plane_type_property,
|
|
|
plane->type);
|
|
plane->type);
|
|
|
|
|
|
|
|
- out:
|
|
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
-
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_universal_plane_init);
|
|
EXPORT_SYMBOL(drm_universal_plane_init);
|
|
|
|
|
|
|
@@ -1246,6 +1265,12 @@ void drm_plane_cleanup(struct drm_plane *plane)
|
|
|
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
|
|
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
|
|
|
dev->mode_config.num_overlay_plane--;
|
|
dev->mode_config.num_overlay_plane--;
|
|
|
drm_modeset_unlock_all(dev);
|
|
drm_modeset_unlock_all(dev);
|
|
|
|
|
+
|
|
|
|
|
+ WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
|
|
|
|
|
+ if (plane->state && plane->funcs->atomic_destroy_state)
|
|
|
|
|
+ plane->funcs->atomic_destroy_state(plane, plane->state);
|
|
|
|
|
+
|
|
|
|
|
+ memset(plane, 0, sizeof(*plane));
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_plane_cleanup);
|
|
EXPORT_SYMBOL(drm_plane_cleanup);
|
|
|
|
|
|
|
@@ -1328,6 +1353,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
|
|
|
"PATH", 0);
|
|
"PATH", 0);
|
|
|
dev->mode_config.path_property = dev_path;
|
|
dev->mode_config.path_property = dev_path;
|
|
|
|
|
|
|
|
|
|
+ dev->mode_config.tile_property = drm_property_create(dev,
|
|
|
|
|
+ DRM_MODE_PROP_BLOB |
|
|
|
|
|
+ DRM_MODE_PROP_IMMUTABLE,
|
|
|
|
|
+ "TILE", 0);
|
|
|
|
|
+
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1388,12 +1418,13 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
|
|
|
* responsible for allocating a list of format names and passing them to
|
|
* responsible for allocating a list of format names and passing them to
|
|
|
* this routine.
|
|
* this routine.
|
|
|
*/
|
|
*/
|
|
|
-int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
|
|
|
|
|
|
|
+int drm_mode_create_tv_properties(struct drm_device *dev,
|
|
|
|
|
+ unsigned int num_modes,
|
|
|
char *modes[])
|
|
char *modes[])
|
|
|
{
|
|
{
|
|
|
struct drm_property *tv_selector;
|
|
struct drm_property *tv_selector;
|
|
|
struct drm_property *tv_subconnector;
|
|
struct drm_property *tv_subconnector;
|
|
|
- int i;
|
|
|
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
|
|
if (dev->mode_config.tv_select_subconnector_property)
|
|
if (dev->mode_config.tv_select_subconnector_property)
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1491,7 +1522,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
|
|
|
* connectors.
|
|
* connectors.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
|
|
int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
|
|
|
{
|
|
{
|
|
@@ -1535,6 +1566,30 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev)
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
|
|
EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_create_suggested_offset_properties - create suggests offset properties
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ *
|
|
|
|
|
+ * Create the the suggested x/y offset property for connectors.
|
|
|
|
|
+ */
|
|
|
|
|
+int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
|
|
|
|
|
+{
|
|
|
|
|
+ if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+
|
|
|
|
|
+ dev->mode_config.suggested_x_property =
|
|
|
|
|
+ drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
|
|
|
|
|
+
|
|
|
|
|
+ dev->mode_config.suggested_y_property =
|
|
|
|
|
+ drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
|
|
|
|
|
+
|
|
|
|
|
+ if (dev->mode_config.suggested_x_property == NULL ||
|
|
|
|
|
+ dev->mode_config.suggested_y_property == NULL)
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
|
|
|
|
|
+
|
|
|
static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
|
|
static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
|
|
|
{
|
|
{
|
|
|
uint32_t total_objects = 0;
|
|
uint32_t total_objects = 0;
|
|
@@ -1651,7 +1706,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
|
|
|
* the caller.
|
|
* the caller.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
static int drm_crtc_convert_umode(struct drm_display_mode *out,
|
|
static int drm_crtc_convert_umode(struct drm_display_mode *out,
|
|
|
const struct drm_mode_modeinfo *in)
|
|
const struct drm_mode_modeinfo *in)
|
|
@@ -1694,7 +1749,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getresources(struct drm_device *dev, void *data,
|
|
int drm_mode_getresources(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -1745,7 +1800,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|
|
card_res->count_fbs = fb_count;
|
|
card_res->count_fbs = fb_count;
|
|
|
mutex_unlock(&file_priv->fbs_lock);
|
|
mutex_unlock(&file_priv->fbs_lock);
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
|
|
+ /* mode_config.mutex protects the connector list against e.g. DP MST
|
|
|
|
|
+ * connector hot-adding. CRTC/Plane lists are invariant. */
|
|
|
|
|
+ mutex_lock(&dev->mode_config.mutex);
|
|
|
if (!drm_is_primary_client(file_priv)) {
|
|
if (!drm_is_primary_client(file_priv)) {
|
|
|
|
|
|
|
|
mode_group = NULL;
|
|
mode_group = NULL;
|
|
@@ -1865,7 +1922,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|
|
card_res->count_connectors, card_res->count_encoders);
|
|
card_res->count_connectors, card_res->count_encoders);
|
|
|
|
|
|
|
|
out:
|
|
out:
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
|
|
+ mutex_unlock(&dev->mode_config.mutex);
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1880,26 +1937,22 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getcrtc(struct drm_device *dev,
|
|
int drm_mode_getcrtc(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
|
{
|
|
{
|
|
|
struct drm_mode_crtc *crtc_resp = data;
|
|
struct drm_mode_crtc *crtc_resp = data;
|
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc *crtc;
|
|
|
- int ret = 0;
|
|
|
|
|
|
|
|
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
-
|
|
|
|
|
crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
|
|
crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
|
|
|
- if (!crtc) {
|
|
|
|
|
- ret = -ENOENT;
|
|
|
|
|
- goto out;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!crtc)
|
|
|
|
|
+ return -ENOENT;
|
|
|
|
|
|
|
|
|
|
+ drm_modeset_lock_crtc(crtc, crtc->primary);
|
|
|
crtc_resp->x = crtc->x;
|
|
crtc_resp->x = crtc->x;
|
|
|
crtc_resp->y = crtc->y;
|
|
crtc_resp->y = crtc->y;
|
|
|
crtc_resp->gamma_size = crtc->gamma_size;
|
|
crtc_resp->gamma_size = crtc->gamma_size;
|
|
@@ -1916,10 +1969,9 @@ int drm_mode_getcrtc(struct drm_device *dev,
|
|
|
} else {
|
|
} else {
|
|
|
crtc_resp->mode_valid = 0;
|
|
crtc_resp->mode_valid = 0;
|
|
|
}
|
|
}
|
|
|
|
|
+ drm_modeset_unlock_crtc(crtc);
|
|
|
|
|
|
|
|
-out:
|
|
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
|
|
static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
|
|
@@ -1935,6 +1987,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
|
|
|
|
|
+{
|
|
|
|
|
+ /* For atomic drivers only state objects are synchronously updated and
|
|
|
|
|
+ * protected by modeset locks, so check those first. */
|
|
|
|
|
+ if (connector->state)
|
|
|
|
|
+ return connector->state->best_encoder;
|
|
|
|
|
+ return connector->encoder;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* drm_mode_getconnector - get connector configuration
|
|
* drm_mode_getconnector - get connector configuration
|
|
|
* @dev: drm device for the ioctl
|
|
* @dev: drm device for the ioctl
|
|
@@ -1946,13 +2007,14 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
|
{
|
|
{
|
|
|
struct drm_mode_get_connector *out_resp = data;
|
|
struct drm_mode_get_connector *out_resp = data;
|
|
|
struct drm_connector *connector;
|
|
struct drm_connector *connector;
|
|
|
|
|
+ struct drm_encoder *encoder;
|
|
|
struct drm_display_mode *mode;
|
|
struct drm_display_mode *mode;
|
|
|
int mode_count = 0;
|
|
int mode_count = 0;
|
|
|
int props_count = 0;
|
|
int props_count = 0;
|
|
@@ -2008,8 +2070,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
|
out_resp->subpixel = connector->display_info.subpixel_order;
|
|
out_resp->subpixel = connector->display_info.subpixel_order;
|
|
|
out_resp->connection = connector->status;
|
|
out_resp->connection = connector->status;
|
|
|
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
|
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
|
|
- if (connector->encoder)
|
|
|
|
|
- out_resp->encoder_id = connector->encoder->base.id;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ encoder = drm_connector_get_encoder(connector);
|
|
|
|
|
+ if (encoder)
|
|
|
|
|
+ out_resp->encoder_id = encoder->base.id;
|
|
|
else
|
|
else
|
|
|
out_resp->encoder_id = 0;
|
|
out_resp->encoder_id = 0;
|
|
|
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
@@ -2079,6 +2143,33 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_connector *connector;
|
|
|
|
|
+ struct drm_device *dev = encoder->dev;
|
|
|
|
|
+ bool uses_atomic = false;
|
|
|
|
|
+
|
|
|
|
|
+ /* For atomic drivers only state objects are synchronously updated and
|
|
|
|
|
+ * protected by modeset locks, so check those first. */
|
|
|
|
|
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
|
|
|
|
+ if (!connector->state)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ uses_atomic = true;
|
|
|
|
|
+
|
|
|
|
|
+ if (connector->state->best_encoder != encoder)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ return connector->state->crtc;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Don't return stale data (e.g. pending async disable). */
|
|
|
|
|
+ if (uses_atomic)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+
|
|
|
|
|
+ return encoder->crtc;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* drm_mode_getencoder - get encoder configuration
|
|
* drm_mode_getencoder - get encoder configuration
|
|
|
* @dev: drm device for the ioctl
|
|
* @dev: drm device for the ioctl
|
|
@@ -2090,37 +2181,38 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getencoder(struct drm_device *dev, void *data,
|
|
int drm_mode_getencoder(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
|
{
|
|
{
|
|
|
struct drm_mode_get_encoder *enc_resp = data;
|
|
struct drm_mode_get_encoder *enc_resp = data;
|
|
|
struct drm_encoder *encoder;
|
|
struct drm_encoder *encoder;
|
|
|
- int ret = 0;
|
|
|
|
|
|
|
+ struct drm_crtc *crtc;
|
|
|
|
|
|
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
encoder = drm_encoder_find(dev, enc_resp->encoder_id);
|
|
encoder = drm_encoder_find(dev, enc_resp->encoder_id);
|
|
|
- if (!encoder) {
|
|
|
|
|
- ret = -ENOENT;
|
|
|
|
|
- goto out;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!encoder)
|
|
|
|
|
+ return -ENOENT;
|
|
|
|
|
|
|
|
- if (encoder->crtc)
|
|
|
|
|
|
|
+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
|
|
|
|
+ crtc = drm_encoder_get_crtc(encoder);
|
|
|
|
|
+ if (crtc)
|
|
|
|
|
+ enc_resp->crtc_id = crtc->base.id;
|
|
|
|
|
+ else if (encoder->crtc)
|
|
|
enc_resp->crtc_id = encoder->crtc->base.id;
|
|
enc_resp->crtc_id = encoder->crtc->base.id;
|
|
|
else
|
|
else
|
|
|
enc_resp->crtc_id = 0;
|
|
enc_resp->crtc_id = 0;
|
|
|
|
|
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
|
|
|
+
|
|
|
enc_resp->encoder_type = encoder->encoder_type;
|
|
enc_resp->encoder_type = encoder->encoder_type;
|
|
|
enc_resp->encoder_id = encoder->base.id;
|
|
enc_resp->encoder_id = encoder->base.id;
|
|
|
enc_resp->possible_crtcs = encoder->possible_crtcs;
|
|
enc_resp->possible_crtcs = encoder->possible_crtcs;
|
|
|
enc_resp->possible_clones = encoder->possible_clones;
|
|
enc_resp->possible_clones = encoder->possible_clones;
|
|
|
|
|
|
|
|
-out:
|
|
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2134,7 +2226,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -2143,13 +2235,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
|
struct drm_mode_config *config;
|
|
struct drm_mode_config *config;
|
|
|
struct drm_plane *plane;
|
|
struct drm_plane *plane;
|
|
|
uint32_t __user *plane_ptr;
|
|
uint32_t __user *plane_ptr;
|
|
|
- int copied = 0, ret = 0;
|
|
|
|
|
|
|
+ int copied = 0;
|
|
|
unsigned num_planes;
|
|
unsigned num_planes;
|
|
|
|
|
|
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
config = &dev->mode_config;
|
|
config = &dev->mode_config;
|
|
|
|
|
|
|
|
if (file_priv->universal_planes)
|
|
if (file_priv->universal_planes)
|
|
@@ -2165,6 +2256,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
|
(plane_resp->count_planes >= num_planes)) {
|
|
(plane_resp->count_planes >= num_planes)) {
|
|
|
plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
|
|
plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
|
|
|
|
|
|
|
|
|
|
+ /* Plane lists are invariant, no locking needed. */
|
|
|
list_for_each_entry(plane, &config->plane_list, head) {
|
|
list_for_each_entry(plane, &config->plane_list, head) {
|
|
|
/*
|
|
/*
|
|
|
* Unless userspace set the 'universal planes'
|
|
* Unless userspace set the 'universal planes'
|
|
@@ -2174,18 +2266,14 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
|
!file_priv->universal_planes)
|
|
!file_priv->universal_planes)
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
- if (put_user(plane->base.id, plane_ptr + copied)) {
|
|
|
|
|
- ret = -EFAULT;
|
|
|
|
|
- goto out;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (put_user(plane->base.id, plane_ptr + copied))
|
|
|
|
|
+ return -EFAULT;
|
|
|
copied++;
|
|
copied++;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
plane_resp->count_planes = num_planes;
|
|
plane_resp->count_planes = num_planes;
|
|
|
|
|
|
|
|
-out:
|
|
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2199,7 +2287,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getplane(struct drm_device *dev, void *data,
|
|
int drm_mode_getplane(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -2207,18 +2295,15 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
|
|
|
struct drm_mode_get_plane *plane_resp = data;
|
|
struct drm_mode_get_plane *plane_resp = data;
|
|
|
struct drm_plane *plane;
|
|
struct drm_plane *plane;
|
|
|
uint32_t __user *format_ptr;
|
|
uint32_t __user *format_ptr;
|
|
|
- int ret = 0;
|
|
|
|
|
|
|
|
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- drm_modeset_lock_all(dev);
|
|
|
|
|
plane = drm_plane_find(dev, plane_resp->plane_id);
|
|
plane = drm_plane_find(dev, plane_resp->plane_id);
|
|
|
- if (!plane) {
|
|
|
|
|
- ret = -ENOENT;
|
|
|
|
|
- goto out;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!plane)
|
|
|
|
|
+ return -ENOENT;
|
|
|
|
|
|
|
|
|
|
+ drm_modeset_lock(&plane->mutex, NULL);
|
|
|
if (plane->crtc)
|
|
if (plane->crtc)
|
|
|
plane_resp->crtc_id = plane->crtc->base.id;
|
|
plane_resp->crtc_id = plane->crtc->base.id;
|
|
|
else
|
|
else
|
|
@@ -2228,6 +2313,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
|
|
|
plane_resp->fb_id = plane->fb->base.id;
|
|
plane_resp->fb_id = plane->fb->base.id;
|
|
|
else
|
|
else
|
|
|
plane_resp->fb_id = 0;
|
|
plane_resp->fb_id = 0;
|
|
|
|
|
+ drm_modeset_unlock(&plane->mutex);
|
|
|
|
|
|
|
|
plane_resp->plane_id = plane->base.id;
|
|
plane_resp->plane_id = plane->base.id;
|
|
|
plane_resp->possible_crtcs = plane->possible_crtcs;
|
|
plane_resp->possible_crtcs = plane->possible_crtcs;
|
|
@@ -2243,15 +2329,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
|
|
|
if (copy_to_user(format_ptr,
|
|
if (copy_to_user(format_ptr,
|
|
|
plane->format_types,
|
|
plane->format_types,
|
|
|
sizeof(uint32_t) * plane->format_count)) {
|
|
sizeof(uint32_t) * plane->format_count)) {
|
|
|
- ret = -EFAULT;
|
|
|
|
|
- goto out;
|
|
|
|
|
|
|
+ return -EFAULT;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
plane_resp->count_format_types = plane->format_count;
|
|
plane_resp->count_format_types = plane->format_count;
|
|
|
|
|
|
|
|
-out:
|
|
|
|
|
- drm_modeset_unlock_all(dev);
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2274,7 +2357,7 @@ static int __setplane_internal(struct drm_plane *plane,
|
|
|
{
|
|
{
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
unsigned int fb_width, fb_height;
|
|
unsigned int fb_width, fb_height;
|
|
|
- int i;
|
|
|
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
|
|
/* No fb means shut it down */
|
|
/* No fb means shut it down */
|
|
|
if (!fb) {
|
|
if (!fb) {
|
|
@@ -2378,13 +2461,12 @@ static int setplane_internal(struct drm_plane *plane,
|
|
|
* valid crtc).
|
|
* valid crtc).
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
|
{
|
|
{
|
|
|
struct drm_mode_set_plane *plane_req = data;
|
|
struct drm_mode_set_plane *plane_req = data;
|
|
|
- struct drm_mode_object *obj;
|
|
|
|
|
struct drm_plane *plane;
|
|
struct drm_plane *plane;
|
|
|
struct drm_crtc *crtc = NULL;
|
|
struct drm_crtc *crtc = NULL;
|
|
|
struct drm_framebuffer *fb = NULL;
|
|
struct drm_framebuffer *fb = NULL;
|
|
@@ -2407,14 +2489,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
|
* First, find the plane, crtc, and fb objects. If not available,
|
|
* First, find the plane, crtc, and fb objects. If not available,
|
|
|
* we don't bother to call the driver.
|
|
* we don't bother to call the driver.
|
|
|
*/
|
|
*/
|
|
|
- obj = drm_mode_object_find(dev, plane_req->plane_id,
|
|
|
|
|
- DRM_MODE_OBJECT_PLANE);
|
|
|
|
|
- if (!obj) {
|
|
|
|
|
|
|
+ plane = drm_plane_find(dev, plane_req->plane_id);
|
|
|
|
|
+ if (!plane) {
|
|
|
DRM_DEBUG_KMS("Unknown plane ID %d\n",
|
|
DRM_DEBUG_KMS("Unknown plane ID %d\n",
|
|
|
plane_req->plane_id);
|
|
plane_req->plane_id);
|
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
}
|
|
}
|
|
|
- plane = obj_to_plane(obj);
|
|
|
|
|
|
|
|
|
|
if (plane_req->fb_id) {
|
|
if (plane_req->fb_id) {
|
|
|
fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
|
|
fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
|
|
@@ -2424,14 +2504,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- obj = drm_mode_object_find(dev, plane_req->crtc_id,
|
|
|
|
|
- DRM_MODE_OBJECT_CRTC);
|
|
|
|
|
- if (!obj) {
|
|
|
|
|
|
|
+ crtc = drm_crtc_find(dev, plane_req->crtc_id);
|
|
|
|
|
+ if (!crtc) {
|
|
|
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
|
|
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
|
|
|
plane_req->crtc_id);
|
|
plane_req->crtc_id);
|
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
}
|
|
}
|
|
|
- crtc = obj_to_crtc(obj);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2453,7 +2531,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|
|
* interface. The only thing it adds is correct refcounting dance.
|
|
* interface. The only thing it adds is correct refcounting dance.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_set_config_internal(struct drm_mode_set *set)
|
|
int drm_mode_set_config_internal(struct drm_mode_set *set)
|
|
|
{
|
|
{
|
|
@@ -2546,7 +2624,7 @@ EXPORT_SYMBOL(drm_crtc_check_viewport);
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|
int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -2709,7 +2787,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|
|
* userspace wants to make use of these capabilities.
|
|
* userspace wants to make use of these capabilities.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
|
static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
|
|
struct drm_mode_cursor2 *req,
|
|
struct drm_mode_cursor2 *req,
|
|
@@ -2810,7 +2888,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|
|
* If this crtc has a universal cursor plane, call that plane's update
|
|
* If this crtc has a universal cursor plane, call that plane's update
|
|
|
* handler rather than using legacy cursor handlers.
|
|
* handler rather than using legacy cursor handlers.
|
|
|
*/
|
|
*/
|
|
|
- drm_modeset_lock_crtc(crtc);
|
|
|
|
|
|
|
+ drm_modeset_lock_crtc(crtc, crtc->cursor);
|
|
|
if (crtc->cursor) {
|
|
if (crtc->cursor) {
|
|
|
ret = drm_mode_cursor_universal(crtc, req, file_priv);
|
|
ret = drm_mode_cursor_universal(crtc, req, file_priv);
|
|
|
goto out;
|
|
goto out;
|
|
@@ -2857,7 +2935,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_cursor_ioctl(struct drm_device *dev,
|
|
int drm_mode_cursor_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -2884,7 +2962,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_cursor2_ioctl(struct drm_device *dev,
|
|
int drm_mode_cursor2_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -2943,23 +3021,21 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
|
|
|
* @file_priv: drm file for the ioctl call
|
|
* @file_priv: drm file for the ioctl call
|
|
|
*
|
|
*
|
|
|
* Add a new FB to the specified CRTC, given a user request. This is the
|
|
* Add a new FB to the specified CRTC, given a user request. This is the
|
|
|
- * original addfb ioclt which only supported RGB formats.
|
|
|
|
|
|
|
+ * original addfb ioctl which only supported RGB formats.
|
|
|
*
|
|
*
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_addfb(struct drm_device *dev,
|
|
int drm_mode_addfb(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
|
{
|
|
{
|
|
|
struct drm_mode_fb_cmd *or = data;
|
|
struct drm_mode_fb_cmd *or = data;
|
|
|
struct drm_mode_fb_cmd2 r = {};
|
|
struct drm_mode_fb_cmd2 r = {};
|
|
|
- struct drm_mode_config *config = &dev->mode_config;
|
|
|
|
|
- struct drm_framebuffer *fb;
|
|
|
|
|
- int ret = 0;
|
|
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
- /* Use new struct with format internally */
|
|
|
|
|
|
|
+ /* convert to new format and call new ioctl */
|
|
|
r.fb_id = or->fb_id;
|
|
r.fb_id = or->fb_id;
|
|
|
r.width = or->width;
|
|
r.width = or->width;
|
|
|
r.height = or->height;
|
|
r.height = or->height;
|
|
@@ -2967,28 +3043,13 @@ int drm_mode_addfb(struct drm_device *dev,
|
|
|
r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
|
|
r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
|
|
|
r.handles[0] = or->handle;
|
|
r.handles[0] = or->handle;
|
|
|
|
|
|
|
|
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
|
|
- return -EINVAL;
|
|
|
|
|
-
|
|
|
|
|
- if ((config->min_width > r.width) || (r.width > config->max_width))
|
|
|
|
|
- return -EINVAL;
|
|
|
|
|
-
|
|
|
|
|
- if ((config->min_height > r.height) || (r.height > config->max_height))
|
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
|
+ ret = drm_mode_addfb2(dev, &r, file_priv);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
- fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
|
|
|
|
|
- if (IS_ERR(fb)) {
|
|
|
|
|
- DRM_DEBUG_KMS("could not create framebuffer\n");
|
|
|
|
|
- return PTR_ERR(fb);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ or->fb_id = r.fb_id;
|
|
|
|
|
|
|
|
- mutex_lock(&file_priv->fbs_lock);
|
|
|
|
|
- or->fb_id = fb->base.id;
|
|
|
|
|
- list_add(&fb->filp_head, &file_priv->fbs);
|
|
|
|
|
- DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
|
|
|
|
|
- mutex_unlock(&file_priv->fbs_lock);
|
|
|
|
|
-
|
|
|
|
|
- return ret;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int format_check(const struct drm_mode_fb_cmd2 *r)
|
|
static int format_check(const struct drm_mode_fb_cmd2 *r)
|
|
@@ -3080,7 +3141,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
|
|
|
num_planes = drm_format_num_planes(r->pixel_format);
|
|
num_planes = drm_format_num_planes(r->pixel_format);
|
|
|
|
|
|
|
|
if (r->width == 0 || r->width % hsub) {
|
|
if (r->width == 0 || r->width % hsub) {
|
|
|
- DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
|
|
|
|
|
|
|
+ DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -3170,7 +3231,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_addfb2(struct drm_device *dev,
|
|
int drm_mode_addfb2(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -3198,7 +3259,7 @@ int drm_mode_addfb2(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_rmfb(struct drm_device *dev,
|
|
int drm_mode_rmfb(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -3252,7 +3313,7 @@ int drm_mode_rmfb(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getfb(struct drm_device *dev,
|
|
int drm_mode_getfb(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -3313,7 +3374,7 @@ int drm_mode_getfb(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
|
|
int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -3393,7 +3454,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
void drm_fb_release(struct drm_file *priv)
|
|
void drm_fb_release(struct drm_file *priv)
|
|
|
{
|
|
{
|
|
@@ -3402,7 +3463,7 @@ void drm_fb_release(struct drm_file *priv)
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* When the file gets released that means no one else can access the fb
|
|
* When the file gets released that means no one else can access the fb
|
|
|
- * list any more, so no need to grab fpriv->fbs_lock. And we need to to
|
|
|
|
|
|
|
+ * list any more, so no need to grab fpriv->fbs_lock. And we need to
|
|
|
* avoid upsetting lockdep since the universal cursor code adds a
|
|
* avoid upsetting lockdep since the universal cursor code adds a
|
|
|
* framebuffer while holding mutex locks.
|
|
* framebuffer while holding mutex locks.
|
|
|
*
|
|
*
|
|
@@ -3435,6 +3496,10 @@ void drm_fb_release(struct drm_file *priv)
|
|
|
* object with drm_object_attach_property. The returned property object must be
|
|
* object with drm_object_attach_property. The returned property object must be
|
|
|
* freed with drm_property_destroy.
|
|
* freed with drm_property_destroy.
|
|
|
*
|
|
*
|
|
|
|
|
+ * Note that the DRM core keeps a per-device list of properties and that, if
|
|
|
|
|
+ * drm_mode_config_cleanup() is called, it will destroy all properties created
|
|
|
|
|
+ * by the driver.
|
|
|
|
|
+ *
|
|
|
* Returns:
|
|
* Returns:
|
|
|
* A pointer to the newly created property on success, NULL on failure.
|
|
* A pointer to the newly created property on success, NULL on failure.
|
|
|
*/
|
|
*/
|
|
@@ -3462,7 +3527,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
|
|
|
|
|
|
|
property->flags = flags;
|
|
property->flags = flags;
|
|
|
property->num_values = num_values;
|
|
property->num_values = num_values;
|
|
|
- INIT_LIST_HEAD(&property->enum_blob_list);
|
|
|
|
|
|
|
+ INIT_LIST_HEAD(&property->enum_list);
|
|
|
|
|
|
|
|
if (name) {
|
|
if (name) {
|
|
|
strncpy(property->name, name, DRM_PROP_NAME_LEN);
|
|
strncpy(property->name, name, DRM_PROP_NAME_LEN);
|
|
@@ -3611,7 +3676,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
|
|
|
* object with drm_object_attach_property. The returned property object must be
|
|
* object with drm_object_attach_property. The returned property object must be
|
|
|
* freed with drm_property_destroy.
|
|
* freed with drm_property_destroy.
|
|
|
*
|
|
*
|
|
|
- * Userspace is allowed to set any interger value in the (min, max) range
|
|
|
|
|
|
|
+ * Userspace is allowed to set any integer value in the (min, max) range
|
|
|
* inclusive.
|
|
* inclusive.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
@@ -3684,8 +3749,8 @@ int drm_property_add_enum(struct drm_property *property, int index,
|
|
|
(value > 63))
|
|
(value > 63))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
- if (!list_empty(&property->enum_blob_list)) {
|
|
|
|
|
- list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
|
|
|
|
|
|
|
+ if (!list_empty(&property->enum_list)) {
|
|
|
|
|
+ list_for_each_entry(prop_enum, &property->enum_list, head) {
|
|
|
if (prop_enum->value == value) {
|
|
if (prop_enum->value == value) {
|
|
|
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
|
|
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
|
|
|
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
|
|
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
|
|
@@ -3703,7 +3768,7 @@ int drm_property_add_enum(struct drm_property *property, int index,
|
|
|
prop_enum->value = value;
|
|
prop_enum->value = value;
|
|
|
|
|
|
|
|
property->values[index] = value;
|
|
property->values[index] = value;
|
|
|
- list_add_tail(&prop_enum->head, &property->enum_blob_list);
|
|
|
|
|
|
|
+ list_add_tail(&prop_enum->head, &property->enum_list);
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_property_add_enum);
|
|
EXPORT_SYMBOL(drm_property_add_enum);
|
|
@@ -3720,7 +3785,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
|
|
|
{
|
|
{
|
|
|
struct drm_property_enum *prop_enum, *pt;
|
|
struct drm_property_enum *prop_enum, *pt;
|
|
|
|
|
|
|
|
- list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
|
|
|
|
|
|
|
+ list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
|
|
|
list_del(&prop_enum->head);
|
|
list_del(&prop_enum->head);
|
|
|
kfree(prop_enum);
|
|
kfree(prop_enum);
|
|
|
}
|
|
}
|
|
@@ -3823,17 +3888,20 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
|
|
|
EXPORT_SYMBOL(drm_object_property_get_value);
|
|
EXPORT_SYMBOL(drm_object_property_get_value);
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * drm_mode_getproperty_ioctl - get the current value of a connector's property
|
|
|
|
|
|
|
+ * drm_mode_getproperty_ioctl - get the property metadata
|
|
|
* @dev: DRM device
|
|
* @dev: DRM device
|
|
|
* @data: ioctl data
|
|
* @data: ioctl data
|
|
|
* @file_priv: DRM file info
|
|
* @file_priv: DRM file info
|
|
|
*
|
|
*
|
|
|
- * This function retrieves the current value for an connectors's property.
|
|
|
|
|
|
|
+ * This function retrieves the metadata for a given property, like the different
|
|
|
|
|
+ * possible values for an enum property or the limits for a range property.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Blob properties are special
|
|
|
*
|
|
*
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -3841,16 +3909,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
|
struct drm_mode_get_property *out_resp = data;
|
|
struct drm_mode_get_property *out_resp = data;
|
|
|
struct drm_property *property;
|
|
struct drm_property *property;
|
|
|
int enum_count = 0;
|
|
int enum_count = 0;
|
|
|
- int blob_count = 0;
|
|
|
|
|
int value_count = 0;
|
|
int value_count = 0;
|
|
|
int ret = 0, i;
|
|
int ret = 0, i;
|
|
|
int copied;
|
|
int copied;
|
|
|
struct drm_property_enum *prop_enum;
|
|
struct drm_property_enum *prop_enum;
|
|
|
struct drm_mode_property_enum __user *enum_ptr;
|
|
struct drm_mode_property_enum __user *enum_ptr;
|
|
|
- struct drm_property_blob *prop_blob;
|
|
|
|
|
- uint32_t __user *blob_id_ptr;
|
|
|
|
|
uint64_t __user *values_ptr;
|
|
uint64_t __user *values_ptr;
|
|
|
- uint32_t __user *blob_length_ptr;
|
|
|
|
|
|
|
|
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -3864,11 +3928,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
|
|
|
|
|
|
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
|
|
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
|
|
|
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
|
|
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
|
|
|
- list_for_each_entry(prop_enum, &property->enum_blob_list, head)
|
|
|
|
|
|
|
+ list_for_each_entry(prop_enum, &property->enum_list, head)
|
|
|
enum_count++;
|
|
enum_count++;
|
|
|
- } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
|
|
|
|
|
- list_for_each_entry(prop_blob, &property->enum_blob_list, head)
|
|
|
|
|
- blob_count++;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
value_count = property->num_values;
|
|
value_count = property->num_values;
|
|
@@ -3893,7 +3954,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
|
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
|
|
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
|
|
|
copied = 0;
|
|
copied = 0;
|
|
|
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
|
|
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
|
|
|
- list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
|
|
|
|
|
|
|
+ list_for_each_entry(prop_enum, &property->enum_list, head) {
|
|
|
|
|
|
|
|
if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
|
|
if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
|
|
|
ret = -EFAULT;
|
|
ret = -EFAULT;
|
|
@@ -3911,35 +3972,24 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
|
|
out_resp->count_enum_blobs = enum_count;
|
|
out_resp->count_enum_blobs = enum_count;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
|
|
|
|
|
- if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
|
|
|
|
|
- copied = 0;
|
|
|
|
|
- blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
|
|
|
|
|
- blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
|
|
|
|
|
-
|
|
|
|
|
- list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
|
|
|
|
|
- if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
|
|
|
|
|
- ret = -EFAULT;
|
|
|
|
|
- goto done;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (put_user(prop_blob->length, blob_length_ptr + copied)) {
|
|
|
|
|
- ret = -EFAULT;
|
|
|
|
|
- goto done;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- copied++;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- out_resp->count_enum_blobs = blob_count;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
+ * NOTE: The idea seems to have been to use this to read all the blob
|
|
|
|
|
+ * property values. But nothing ever added them to the corresponding
|
|
|
|
|
+ * list, userspace always used the special-purpose get_blob ioctl to
|
|
|
|
|
+ * read the value for a blob property. It also doesn't make a lot of
|
|
|
|
|
+ * sense to return values here when everything else is just metadata for
|
|
|
|
|
+ * the property itself.
|
|
|
|
|
+ */
|
|
|
|
|
+ if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
|
|
|
|
|
+ out_resp->count_enum_blobs = 0;
|
|
|
done:
|
|
done:
|
|
|
drm_modeset_unlock_all(dev);
|
|
drm_modeset_unlock_all(dev);
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
|
|
|
|
|
- void *data)
|
|
|
|
|
|
|
+static struct drm_property_blob *
|
|
|
|
|
+drm_property_create_blob(struct drm_device *dev, size_t length,
|
|
|
|
|
+ const void *data)
|
|
|
{
|
|
{
|
|
|
struct drm_property_blob *blob;
|
|
struct drm_property_blob *blob;
|
|
|
int ret;
|
|
int ret;
|
|
@@ -3985,7 +4035,7 @@ static void drm_property_destroy_blob(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_getblob_ioctl(struct drm_device *dev,
|
|
int drm_mode_getblob_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4019,12 +4069,25 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_connector_set_path_property - set tile property on connector
|
|
|
|
|
+ * @connector: connector to set property on.
|
|
|
|
|
+ * @path: path to use for property.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This creates a property to expose to userspace to specify a
|
|
|
|
|
+ * connector path. This is mainly used for DisplayPort MST where
|
|
|
|
|
+ * connectors have a topology and we want to allow userspace to give
|
|
|
|
|
+ * them more meaningful names.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returns:
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
|
|
+ */
|
|
|
int drm_mode_connector_set_path_property(struct drm_connector *connector,
|
|
int drm_mode_connector_set_path_property(struct drm_connector *connector,
|
|
|
- char *path)
|
|
|
|
|
|
|
+ const char *path)
|
|
|
{
|
|
{
|
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_device *dev = connector->dev;
|
|
|
- int ret, size;
|
|
|
|
|
- size = strlen(path) + 1;
|
|
|
|
|
|
|
+ size_t size = strlen(path) + 1;
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
connector->path_blob_ptr = drm_property_create_blob(connector->dev,
|
|
connector->path_blob_ptr = drm_property_create_blob(connector->dev,
|
|
|
size, path);
|
|
size, path);
|
|
@@ -4038,6 +4101,52 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
|
|
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_connector_set_tile_property - set tile property on connector
|
|
|
|
|
+ * @connector: connector to set property on.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This looks up the tile information for a connector, and creates a
|
|
|
|
|
+ * property for userspace to parse if it exists. The property is of
|
|
|
|
|
+ * the form of 8 integers using ':' as a separator.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returns:
|
|
|
|
|
+ * Zero on success, errno on failure.
|
|
|
|
|
+ */
|
|
|
|
|
+int drm_mode_connector_set_tile_property(struct drm_connector *connector)
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_device *dev = connector->dev;
|
|
|
|
|
+ int ret, size;
|
|
|
|
|
+ char tile[256];
|
|
|
|
|
+
|
|
|
|
|
+ if (connector->tile_blob_ptr)
|
|
|
|
|
+ drm_property_destroy_blob(dev, connector->tile_blob_ptr);
|
|
|
|
|
+
|
|
|
|
|
+ if (!connector->has_tile) {
|
|
|
|
|
+ connector->tile_blob_ptr = NULL;
|
|
|
|
|
+ ret = drm_object_property_set_value(&connector->base,
|
|
|
|
|
+ dev->mode_config.tile_property, 0);
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
|
|
|
|
|
+ connector->tile_group->id, connector->tile_is_single_monitor,
|
|
|
|
|
+ connector->num_h_tile, connector->num_v_tile,
|
|
|
|
|
+ connector->tile_h_loc, connector->tile_v_loc,
|
|
|
|
|
+ connector->tile_h_size, connector->tile_v_size);
|
|
|
|
|
+ size = strlen(tile) + 1;
|
|
|
|
|
+
|
|
|
|
|
+ connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
|
|
|
|
|
+ size, tile);
|
|
|
|
|
+ if (!connector->tile_blob_ptr)
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ ret = drm_object_property_set_value(&connector->base,
|
|
|
|
|
+ dev->mode_config.tile_property,
|
|
|
|
|
+ connector->tile_blob_ptr->base.id);
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* drm_mode_connector_update_edid_property - update the edid property of a connector
|
|
* drm_mode_connector_update_edid_property - update the edid property of a connector
|
|
|
* @connector: drm connector
|
|
* @connector: drm connector
|
|
@@ -4047,13 +4156,14 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property);
|
|
|
* connector's edid property.
|
|
* connector's edid property.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
|
int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
|
|
- struct edid *edid)
|
|
|
|
|
|
|
+ const struct edid *edid)
|
|
|
{
|
|
{
|
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_device *dev = connector->dev;
|
|
|
- int ret, size;
|
|
|
|
|
|
|
+ size_t size;
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
/* ignore requests to set edid when overridden */
|
|
/* ignore requests to set edid when overridden */
|
|
|
if (connector->override_edid)
|
|
if (connector->override_edid)
|
|
@@ -4143,7 +4253,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
|
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4226,7 +4336,7 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
|
|
|
EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
|
|
EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * drm_mode_getproperty_ioctl - get the current value of a object's property
|
|
|
|
|
|
|
+ * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
|
|
|
* @dev: DRM device
|
|
* @dev: DRM device
|
|
|
* @data: ioctl data
|
|
* @data: ioctl data
|
|
|
* @file_priv: DRM file info
|
|
* @file_priv: DRM file info
|
|
@@ -4238,7 +4348,7 @@ EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
|
|
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -4310,7 +4420,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
|
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
struct drm_file *file_priv)
|
|
@@ -4382,7 +4492,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
|
|
|
* possible_clones and possible_crtcs bitmasks.
|
|
* possible_clones and possible_crtcs bitmasks.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_connector_attach_encoder(struct drm_connector *connector,
|
|
int drm_mode_connector_attach_encoder(struct drm_connector *connector,
|
|
|
struct drm_encoder *encoder)
|
|
struct drm_encoder *encoder)
|
|
@@ -4409,7 +4519,7 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
|
|
|
* fixed gamma table size.
|
|
* fixed gamma table size.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
|
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
|
|
int gamma_size)
|
|
int gamma_size)
|
|
@@ -4438,7 +4548,7 @@ EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
|
int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4510,7 +4620,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
|
|
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4576,7 +4686,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4599,7 +4709,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
|
if (!crtc)
|
|
if (!crtc)
|
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
- drm_modeset_lock_crtc(crtc);
|
|
|
|
|
|
|
+ drm_modeset_lock_crtc(crtc, crtc->primary);
|
|
|
if (crtc->primary->fb == NULL) {
|
|
if (crtc->primary->fb == NULL) {
|
|
|
/* The framebuffer is currently unbound, presumably
|
|
/* The framebuffer is currently unbound, presumably
|
|
|
* due to a hotplug event, that userspace has not
|
|
* due to a hotplug event, that userspace has not
|
|
@@ -4742,7 +4852,7 @@ EXPORT_SYMBOL(drm_mode_config_reset);
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
|
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4769,6 +4879,16 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
|
|
if (PAGE_ALIGN(size) == 0)
|
|
if (PAGE_ALIGN(size) == 0)
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
|
+ * handle, pitch and size are output parameters. Zero them out to
|
|
|
|
|
+ * prevent drivers from accidentally using uninitialized data. Since
|
|
|
|
|
+ * not all existing userspace is clearing these fields properly we
|
|
|
|
|
+ * cannot reject IOCTL with garbage in them.
|
|
|
|
|
+ */
|
|
|
|
|
+ args->handle = 0;
|
|
|
|
|
+ args->pitch = 0;
|
|
|
|
|
+ args->size = 0;
|
|
|
|
|
+
|
|
|
return dev->driver->dumb_create(file_priv, dev, args);
|
|
return dev->driver->dumb_create(file_priv, dev, args);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -4784,7 +4904,7 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
|
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -4811,7 +4931,7 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
|
|
* Called by the user via ioctl.
|
|
* Called by the user via ioctl.
|
|
|
*
|
|
*
|
|
|
* Returns:
|
|
* Returns:
|
|
|
- * Zero on success, errno on failure.
|
|
|
|
|
|
|
+ * Zero on success, negative errno on failure.
|
|
|
*/
|
|
*/
|
|
|
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
|
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
void *data, struct drm_file *file_priv)
|
|
@@ -5097,6 +5217,7 @@ void drm_mode_config_init(struct drm_device *dev)
|
|
|
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
|
|
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
|
|
|
INIT_LIST_HEAD(&dev->mode_config.plane_list);
|
|
INIT_LIST_HEAD(&dev->mode_config.plane_list);
|
|
|
idr_init(&dev->mode_config.crtc_idr);
|
|
idr_init(&dev->mode_config.crtc_idr);
|
|
|
|
|
+ idr_init(&dev->mode_config.tile_idr);
|
|
|
|
|
|
|
|
drm_modeset_lock_all(dev);
|
|
drm_modeset_lock_all(dev);
|
|
|
drm_mode_create_standard_connector_properties(dev);
|
|
drm_mode_create_standard_connector_properties(dev);
|
|
@@ -5184,6 +5305,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
|
|
crtc->funcs->destroy(crtc);
|
|
crtc->funcs->destroy(crtc);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ idr_destroy(&dev->mode_config.tile_idr);
|
|
|
idr_destroy(&dev->mode_config.crtc_idr);
|
|
idr_destroy(&dev->mode_config.crtc_idr);
|
|
|
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
|
|
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
|
|
|
}
|
|
}
|
|
@@ -5206,3 +5328,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
|
|
|
supported_rotations);
|
|
supported_rotations);
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL(drm_mode_create_rotation_property);
|
|
EXPORT_SYMBOL(drm_mode_create_rotation_property);
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * DOC: Tile group
|
|
|
|
|
+ *
|
|
|
|
|
+ * Tile groups are used to represent tiled monitors with a unique
|
|
|
|
|
+ * integer identifier. Tiled monitors using DisplayID v1.3 have
|
|
|
|
|
+ * a unique 8-byte handle, we store this in a tile group, so we
|
|
|
|
|
+ * have a common identifier for all tiles in a monitor group.
|
|
|
|
|
+ */
|
|
|
|
|
+static void drm_tile_group_free(struct kref *kref)
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
|
|
|
|
|
+ struct drm_device *dev = tg->dev;
|
|
|
|
|
+ mutex_lock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ idr_remove(&dev->mode_config.tile_idr, tg->id);
|
|
|
|
|
+ mutex_unlock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ kfree(tg);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_put_tile_group - drop a reference to a tile group.
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @tg: tile group to drop reference to.
|
|
|
|
|
+ *
|
|
|
|
|
+ * drop reference to tile group and free if 0.
|
|
|
|
|
+ */
|
|
|
|
|
+void drm_mode_put_tile_group(struct drm_device *dev,
|
|
|
|
|
+ struct drm_tile_group *tg)
|
|
|
|
|
+{
|
|
|
|
|
+ kref_put(&tg->refcount, drm_tile_group_free);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_get_tile_group - get a reference to an existing tile group
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @topology: 8-bytes unique per monitor.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Use the unique bytes to get a reference to an existing tile group.
|
|
|
|
|
+ *
|
|
|
|
|
+ * RETURNS:
|
|
|
|
|
+ * tile group or NULL if not found.
|
|
|
|
|
+ */
|
|
|
|
|
+struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
|
|
|
|
|
+ char topology[8])
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_tile_group *tg;
|
|
|
|
|
+ int id;
|
|
|
|
|
+ mutex_lock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
|
|
|
|
|
+ if (!memcmp(tg->group_data, topology, 8)) {
|
|
|
|
|
+ if (!kref_get_unless_zero(&tg->refcount))
|
|
|
|
|
+ tg = NULL;
|
|
|
|
|
+ mutex_unlock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ return tg;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ mutex_unlock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * drm_mode_create_tile_group - create a tile group from a displayid description
|
|
|
|
|
+ * @dev: DRM device
|
|
|
|
|
+ * @topology: 8-bytes unique per monitor.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Create a tile group for the unique monitor, and get a unique
|
|
|
|
|
+ * identifier for the tile group.
|
|
|
|
|
+ *
|
|
|
|
|
+ * RETURNS:
|
|
|
|
|
+ * new tile group or error.
|
|
|
|
|
+ */
|
|
|
|
|
+struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
|
|
|
|
|
+ char topology[8])
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_tile_group *tg;
|
|
|
|
|
+ int ret;
|
|
|
|
|
+
|
|
|
|
|
+ tg = kzalloc(sizeof(*tg), GFP_KERNEL);
|
|
|
|
|
+ if (!tg)
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
+
|
|
|
|
|
+ kref_init(&tg->refcount);
|
|
|
|
|
+ memcpy(tg->group_data, topology, 8);
|
|
|
|
|
+ tg->dev = dev;
|
|
|
|
|
+
|
|
|
|
|
+ mutex_lock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
|
|
|
|
|
+ if (ret >= 0) {
|
|
|
|
|
+ tg->id = ret;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ kfree(tg);
|
|
|
|
|
+ tg = ERR_PTR(ret);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&dev->mode_config.idr_mutex);
|
|
|
|
|
+ return tg;
|
|
|
|
|
+}
|