[RFC/PATCH 1/5] drm: Add live source object

Laurent Pinchart
2015-03-15T21:55:40Z

drivers/gpu/drm/drm_crtc.c | 231 ++++++++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_ioctl.c | 3 +
include/drm/drm_crtc.h | 42 ++++++++
include/uapi/drm/drm.h | 4 +
include/uapi/drm/drm_mode.h | 32 ++++++
5 files changed, 312 insertions(+)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5785336695ca..a510c9742a16 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1261,6 +1261,60 @@ void drm_plane_cleanup(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_cleanup);

+int drm_live_source_init(struct drm_device *dev, struct drm_live_source *src,
+ const char *name, unsigned long possible_planes,
+ const uint32_t *formats, uint32_t format_count,
+ const struct drm_live_source_funcs *funcs)
+{
+ int ret;
+
+ drm_modeset_lock_all(dev);
+
+ ret = drm_mode_object_get(dev, &src->base, DRM_MODE_OBJECT_LIVE_SOURCE);
+ if (ret)
+ goto out;
+
+ src->dev = dev;
+ src->funcs = funcs;
+ if (name)
+ strlcpy(src->name, name, DRM_SOURCE_NAME_LEN);
+ src->possible_planes = possible_planes;
+
+ src->format_types = kmalloc(format_count * sizeof(*src->format_types),
+ GFP_KERNEL);
+ if (!src->format_types) {
+ DRM_DEBUG_KMS("out of memory when allocating source foramts\n");
+ drm_mode_object_put(dev, &src->base);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(src->format_types, formats,
+ format_count * sizeof(*src->format_types));
+ src->format_count = format_count;
+
+ list_add_tail(&src->head, &dev->mode_config.live_source_list);
+ dev->mode_config.num_live_source++;
+
+ out:
+ drm_modeset_unlock_all(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_live_source_init);
+
+void drm_live_source_cleanup(struct drm_live_source *src)
+{
+ struct drm_device *dev = src->dev;
+
+ drm_modeset_lock_all(dev);
+ drm_mode_object_put(dev, &src->base);
+ list_del(&src->head);
+ dev->mode_config.num_live_source--;
+ drm_modeset_unlock_all(dev);
+}
+EXPORT_SYMBOL(drm_live_source_cleanup);
+
/**
* drm_plane_index - find the index of a registered plane
* @plane: plane to find index for
@@ -2612,6 +2666,176 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
}

/**
+ * drm_mode_getsource_res - get live source info
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Return a live source and set of IDs.
+ */
+int drm_mode_getsource_res(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mode_get_live_source_res *src_resp = data;
+ struct drm_mode_config *config;
+ struct drm_live_source *src;
+ uint32_t __user *src_ptr;
+ int copied = 0, ret = 0;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ drm_modeset_lock_all(dev);
+ config = &dev->mode_config;
+
+ /*
+ * This ioctl is called twice, once to determine how much space is
+ * needed, and the 2nd time to fill it.
+ */
+ if (config->num_live_source &&
+ (src_resp->count_sources >= config->num_live_source)) {
+ src_ptr = (uint32_t __user *)(unsigned long)src_resp->source_id_ptr;
+
+ list_for_each_entry(src, &config->live_source_list, head) {
+ if (put_user(src->base.id, src_ptr + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ copied++;
+ }
+ }
+ src_resp->count_sources = config->num_live_source;
+
+out:
+ drm_modeset_unlock_all(dev);
+ return ret;
+}
+
+/**
+ * drm_mode_getsource - get live source info
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Return live source info, including formats supported, ...
+ */
+int drm_mode_getsource(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mode_get_live_source *src_resp = data;
+ struct drm_mode_object *obj;
+ struct drm_live_source *src;
+ int ret = 0;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ obj = drm_mode_object_find(dev, src_resp->source_id,
+ DRM_MODE_OBJECT_LIVE_SOURCE);
+ if (!obj)
+ return -ENOENT;
+ src = obj_to_live_source(obj);
+
+ src_resp->source_id = src->base.id;
+ strlcpy(src_resp->name, src->name, DRM_SOURCE_NAME_LEN);
+ src_resp->possible_planes = src->possible_planes;
+
+ drm_modeset_lock_all(dev);
+
+ if (src->plane)
+ src_resp->plane_id = src->plane->base.id;
+ else
+ src_resp->plane_id = 0;
+
+ src_resp->width = src->width;
+ src_resp->height = src->height;
+ src_resp->pixel_format = src->pixel_format;
+
+ /*
+ * This ioctl is called twice, once to determine how much space is
+ * needed, and the 2nd time to fill it.
+ */
+ if (src->format_count &&
+ (src_resp->count_format_types >= src->format_count)) {
+ uint32_t __user *format_ptr;
+
+ format_ptr = (uint32_t __user *)(unsigned long)src_resp->format_type_ptr;
+ if (copy_to_user(format_ptr, src->format_types,
+ sizeof(uint32_t) * src->format_count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ src_resp->count_format_types = src->format_count;
+
+out:
+ drm_modeset_unlock_all(dev);
+ return ret;
+}
+
+/**
+ * drm_mode_setsource - set up or tear down a live source
+ * @dev: DRM device
+ * @data: ioctl data*
+ * @file_priv: DRM file info
+ *
+ * Set live source info, including plane, and other factors.
+ * Or pass a NULL plane to disable.
+ */
+int drm_mode_setsource(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mode_set_live_source *src_req = data;
+ struct drm_mode_object *obj;
+ struct drm_live_source *src;
+ unsigned int i;
+ int ret = 0;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ /*
+ * First, find the live source and plane objects. If not available, we
+ * don't bother to call the driver.
+ */
+ obj = drm_mode_object_find(dev, src_req->source_id,
+ DRM_MODE_OBJECT_LIVE_SOURCE);
+ if (!obj) {
+ DRM_DEBUG_KMS("Unknown live source ID %d\n",
+ src_req->source_id);
+ return -ENOENT;
+ }
+ src = obj_to_live_source(obj);
+
+ drm_modeset_lock_all(dev);
+
+ if (src->plane) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Check whether this source supports the pixel format. */
+ for (i = 0; i < src->format_count; i++)
+ if (src_req->pixel_format == src->format_types[i])
+ break;
+
+ if (i == src->format_count) {
+ DRM_DEBUG_KMS("Invalid pixel format 0x%08x for source %u\n",
+ src_req->pixel_format, src->base.id);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ src->width = src_req->width;
+ src->height = src_req->height;
+ src->pixel_format = src_req->pixel_format;
+
+out:
+ drm_modeset_unlock_all(dev);
+ return ret;
+}
+
+/**
* drm_mode_set_config_internal - helper to call ->set_config
* @set: modeset config to set
*
@@ -5429,6 +5653,7 @@ void drm_mode_config_init(struct drm_device *dev)
INIT_LIST_HEAD(&dev->mode_config.property_list);
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
INIT_LIST_HEAD(&dev->mode_config.plane_list);
+ INIT_LIST_HEAD(&dev->mode_config.live_source_list);
idr_init(&dev->mode_config.crtc_idr);
idr_init(&dev->mode_config.tile_idr);

@@ -5468,6 +5693,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
struct drm_property *property, *pt;
struct drm_property_blob *blob, *bt;
struct drm_plane *plane, *plt;
+ struct drm_live_source *src, *psrc;

list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
head) {
@@ -5507,6 +5733,11 @@ void drm_mode_config_cleanup(struct drm_device *dev)
plane->funcs->destroy(plane);
}

+ list_for_each_entry_safe(src, psrc, &dev->mode_config.live_source_list,
+ head) {
+ src->funcs->destroy(src);
+ }
+
list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
crtc->funcs->destroy(crtc);
}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index a6d773a61c2d..2cb400a8bc8d 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -609,10 +609,13 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),

DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETSOURCERESOURCES, drm_mode_getsource_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETSOURCE, drm_mode_getsource, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETSOURCE, drm_mode_setsource, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index adc9ea5acf02..775a9a84c5bf 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -54,6 +54,7 @@ struct fence;
#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
#define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd
+#define DRM_MODE_OBJECT_LIVE_SOURCE 0xe1e1e1e1
#define DRM_MODE_OBJECT_ANY 0

struct drm_mode_object {
@@ -247,6 +248,7 @@ struct drm_pending_vblank_event;
struct drm_plane;
struct drm_bridge;
struct drm_atomic_state;
+struct drm_live_source;

/**
* struct drm_crtc_state - mutable CRTC state
@@ -869,6 +871,30 @@ struct drm_plane {
struct drm_plane_state *state;
};

+struct drm_live_source_funcs {
+ void (*destroy)(struct drm_live_source *src);
+};
+
+struct drm_live_source {
+ struct drm_device *dev;
+ struct list_head head;
+
+ struct drm_mode_object base;
+
+ char name[DRM_SOURCE_NAME_LEN];
+
+ uint32_t possible_planes;
+ uint32_t *format_types;
+ uint32_t format_count;
+
+ struct drm_plane *plane;
+ unsigned int width;
+ unsigned int height;
+ uint32_t pixel_format;
+
+ const struct drm_live_source_funcs *funcs;
+};
+
/**
* struct drm_bridge_funcs - drm_bridge control functions
* @attach: Called during drm_bridge_attach
@@ -1087,6 +1113,8 @@ struct drm_mode_config {
int num_overlay_plane;
int num_total_plane;
struct list_head plane_list;
+ int num_live_source;
+ struct list_head live_source_list;

int num_crtc;
struct list_head crtc_list;
@@ -1186,6 +1214,7 @@ struct drm_mode_config {
#define obj_to_property(x) container_of(x, struct drm_property, base)
#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
#define obj_to_plane(x) container_of(x, struct drm_plane, base)
+#define obj_to_live_source(x) container_of(x, struct drm_live_source, base)

struct drm_prop_enum_list {
int type;
@@ -1276,6 +1305,13 @@ extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,

extern void drm_encoder_cleanup(struct drm_encoder *encoder);

+extern int drm_live_source_init(struct drm_device *dev,
+ struct drm_live_source *src, const char *name,
+ unsigned long possible_planes,
+ const uint32_t *formats, uint32_t format_count,
+ const struct drm_live_source_funcs *funcs);
+extern void drm_live_source_cleanup(struct drm_live_source *src);
+
extern const char *drm_get_connector_status_name(enum drm_connector_status status);
extern const char *drm_get_subpixel_order_name(enum subpixel_order order);
extern const char *drm_get_dpms_name(int val);
@@ -1391,6 +1427,8 @@ extern int drm_mode_getresources(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int drm_mode_getsource_res(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_mode_getcrtc(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_getconnector(struct drm_device *dev,
@@ -1402,6 +1440,10 @@ extern int drm_mode_getplane(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_setplane(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+extern int drm_mode_getsource(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+extern int drm_mode_setsource(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
extern int drm_mode_cursor_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_cursor2_ioctl(struct drm_device *dev,
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index ff6ef62d084b..d60cb8fa034c 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -787,6 +787,10 @@ struct drm_prime_handle {
#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2)
#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic)

+#define DRM_IOCTL_MODE_GETSOURCERESOURCES DRM_IOWR(0xBC, struct drm_mode_get_live_source_res)
+#define DRM_IOCTL_MODE_GETSOURCE DRM_IOWR(0xBD, struct drm_mode_get_live_source)
+#define DRM_IOCTL_MODE_SETSOURCE DRM_IOWR(0xBE, struct drm_mode_set_live_source)
+
/**
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x9f.
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index dbeba949462a..ecc1fa3000f4 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -33,6 +33,7 @@
#define DRM_CONNECTOR_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
#define DRM_PROP_NAME_LEN 32
+#define DRM_SOURCE_NAME_LEN 32

#define DRM_MODE_TYPE_BUILTIN (1<<0)
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
@@ -179,6 +180,37 @@ struct drm_mode_get_plane_res {
__u32 count_planes;
};

+struct drm_mode_set_live_source {
+ __u32 source_id;
+
+ __u32 plane_id;
+
+ __u32 width;
+ __u32 height;
+ __u32 pixel_format;
+};
+
+struct drm_mode_get_live_source {
+ __u32 source_id;
+ char name[DRM_SOURCE_NAME_LEN];
+
+ __u32 plane_id;
+
+ __u32 possible_planes;
+
+ __u32 count_format_types;
+ __u64 format_type_ptr;
+
+ __u32 width;
+ __u32 height;
+ __u32 pixel_format;
+};
+
+struct drm_mode_get_live_source_res {
+ __u64 source_id_ptr;
+ __u32 count_sources;
+};
+
#define DRM_MODE_ENCODER_NONE 0
#define DRM_MODE_ENCODER_DAC 1
#define DRM_MODE_ENCODER_TMDS 2
--
2.0.5