diff options
author | Daniel Stone <daniels@collabora.com> | 2019-12-16 19:46:43 -0800 |
---|---|---|
committer | Lyude Paul <lyude@redhat.com> | 2020-01-14 16:22:17 -0500 |
commit | 455e00f1412fe51fa7bd21ad6fe0015b163fa9e5 (patch) | |
tree | b9cb95512fa3d435c5f284afa8d219d64b892451 /drivers/gpu/drm/drm_framebuffer.c | |
parent | 7b6bd84336096851225d06f3b176157f305e09a2 (diff) | |
download | linux-455e00f1412fe51fa7bd21ad6fe0015b163fa9e5.tar.gz linux-455e00f1412fe51fa7bd21ad6fe0015b163fa9e5.tar.bz2 linux-455e00f1412fe51fa7bd21ad6fe0015b163fa9e5.zip |
drm: Add getfb2 ioctl
getfb2 allows us to pass multiple planes and modifiers, just like addfb2
over addfb.
Changes since v2:
- add privilege checks from getfb1 since handles should only be
returned to master/root
Changes since v1:
- unused modifiers set to 0 instead of DRM_FORMAT_MOD_INVALID
- update ioctl number
Signed-off-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Juston Li <juston.li@intel.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191217034642.3814-1-juston.li@intel.com
Diffstat (limited to 'drivers/gpu/drm/drm_framebuffer.c')
-rw-r--r-- | drivers/gpu/drm/drm_framebuffer.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 57564318ceea..57ac94ce9b9e 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -31,6 +31,7 @@ #include <drm/drm_file.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem.h> #include <drm/drm_print.h> #include <drm/drm_util.h> @@ -548,7 +549,128 @@ int drm_mode_getfb(struct drm_device *dev, out: drm_framebuffer_put(fb); + return ret; +} + +/** + * drm_mode_getfb2 - get extended FB info + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Lookup the FB given its ID and return info about it. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getfb2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd2 *r = data; + struct drm_framebuffer *fb; + unsigned int i; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id); + if (!fb) + return -ENOENT; + + /* For multi-plane framebuffers, we require the driver to place the + * GEM objects directly in the drm_framebuffer. For single-plane + * framebuffers, we can fall back to create_handle. + */ + if (!fb->obj[0] && + (fb->format->num_planes > 1 || !fb->funcs->create_handle)) { + ret = -ENODEV; + goto out; + } + + r->height = fb->height; + r->width = fb->width; + r->pixel_format = fb->format->format; + + r->flags = 0; + if (dev->mode_config.allow_fb_modifiers) + r->flags |= DRM_MODE_FB_MODIFIERS; + + for (i = 0; i < ARRAY_SIZE(r->handles); i++) { + r->handles[i] = 0; + r->pitches[i] = 0; + r->offsets[i] = 0; + r->modifier[i] = 0; + } + + for (i = 0; i < fb->format->num_planes; i++) { + r->pitches[i] = fb->pitches[i]; + r->offsets[i] = fb->offsets[i]; + if (dev->mode_config.allow_fb_modifiers) + r->modifier[i] = fb->modifier; + } + + /* GET_FB2() is an unprivileged ioctl so we must not return a + * buffer-handle to non master/root processes! To match GET_FB() + * just return invalid handles (0) for non masters/root + * rather than making GET_FB2() privileged. + */ + if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) { + ret = 0; + goto out; + } + for (i = 0; i < fb->format->num_planes; i++) { + int j; + + /* If we reuse the same object for multiple planes, also + * return the same handle. + */ + for (j = 0; j < i; j++) { + if (fb->obj[i] == fb->obj[j]) { + r->handles[i] = r->handles[j]; + break; + } + } + + if (r->handles[i]) + continue; + + if (fb->obj[i]) { + ret = drm_gem_handle_create(file_priv, fb->obj[i], + &r->handles[i]); + } else { + WARN_ON(i > 0); + ret = fb->funcs->create_handle(fb, file_priv, + &r->handles[i]); + } + + if (ret != 0) + goto out; + } + +out: + if (ret != 0) { + /* Delete any previously-created handles on failure. */ + for (i = 0; i < ARRAY_SIZE(r->handles); i++) { + int j; + + if (r->handles[i]) + drm_gem_handle_delete(file_priv, r->handles[i]); + + /* Zero out any handles identical to the one we just + * deleted. + */ + for (j = i + 1; j < ARRAY_SIZE(r->handles); j++) { + if (r->handles[j] == r->handles[i]) + r->handles[j] = 0; + } + } + } + + drm_framebuffer_put(fb); return ret; } |