Overload the getblob ioctl to allow passing in a mode ID, which will
return the userspace representation (drm_mode_modeinfo) of that mode.

Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 drivers/gpu/drm/drm_crtc.c | 26 ++++++++++++++++++++------
 include/drm/drm_crtc.h     |  8 ++++++++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index af9628b..e50eda2 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4163,9 +4163,12 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
        struct drm_mode_get_blob *out_resp = data;
-       struct drm_property_blob *blob;
+       const struct drm_property_blob *blob = NULL;
+       const struct drm_display_mode *mode = NULL;
+       void __user *user_ptr = (void __user *)(unsigned long)out_resp->data;
+       u32 length;
+       const void *data_src;
        int ret = 0;
-       void __user *blob_ptr;

        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
@@ -4173,18 +4176,29 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
        drm_modeset_lock_all(dev);
        blob = drm_property_blob_find(dev, out_resp->blob_id);
        if (!blob) {
+               /* If we don't find a blob, they might be trying to get a mode
+                * instead. */
+               mode = drm_mode_find(dev, out_resp->blob_id);
+       }
+
+       if (blob) {
+               length = blob->length;
+               data_src = blob->data;
+       } else if (mode) {
+               length = sizeof(mode->umode);
+               data_src = &mode->umode;
+       } else {
                ret = -ENOENT;
                goto done;
        }

-       if (out_resp->length == blob->length) {
-               blob_ptr = (void __user *)(unsigned long)out_resp->data;
-               if (copy_to_user(blob_ptr, blob->data, blob->length)) {
+       if (out_resp->length == length) {
+               if (copy_to_user(user_ptr, data_src, length)) {
                        ret = -EFAULT;
                        goto done;
                }
        }
-       out_resp->length = blob->length;
+       out_resp->length = length;

 done:
        drm_modeset_unlock_all(dev);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7683527..3ab70a7 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1533,6 +1533,14 @@ drm_property_blob_find(struct drm_device *dev, uint32_t 
id)
        return mo ? obj_to_blob(mo) : NULL;
 }

+static inline struct drm_display_mode *drm_mode_find(struct drm_device *dev,
+               uint32_t id)
+{
+       struct drm_mode_object *mo;
+       mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_MODE);
+       return mo ? obj_to_mode(mo) : NULL;
+}
+
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, planelist) \
        list_for_each_entry(plane, planelist, head) \
-- 
2.3.2

Reply via email to