@@ -1544,10 +1544,10 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
return true;
}
-int drm_mode_getconnector(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+int drm_mode_getconnector(struct drm_device *dev,
+ struct drm_mode_get_connector *out_resp,
+ struct drm_file *file_priv, bool user)
{
- struct drm_mode_get_connector *out_resp = data;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_display_mode *mode;
@@ -1556,9 +1556,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
int ret = 0;
int copied = 0;
int i;
- struct drm_mode_modeinfo u_mode;
- struct drm_mode_modeinfo __user *mode_ptr;
- uint32_t __user *encoder_ptr;
+ struct drm_mode_modeinfo __user *mode_ptr_user;
+ struct drm_mode_modeinfo u_mode, *mode_ptr;
+ uint32_t __user *encoder_ptr_user;
+ u32 *encoder_ptr;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -1575,13 +1576,18 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
copied = 0;
- encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
+ encoder_ptr_user = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
+ encoder_ptr = (u32 *)(unsigned long)(out_resp->encoders_ptr);
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] != 0) {
- if (put_user(connector->encoder_ids[i],
- encoder_ptr + copied)) {
- ret = -EFAULT;
- goto out;
+ if (user) {
+ if (put_user(connector->encoder_ids[i],
+ encoder_ptr_user + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ } else {
+ encoder_ptr[copied] = connector->encoder_ids[i];
}
copied++;
}
@@ -1616,18 +1622,23 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
*/
if ((out_resp->count_modes >= mode_count) && mode_count) {
copied = 0;
- mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
+ mode_ptr_user = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
+ mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr;
list_for_each_entry(mode, &connector->modes, head) {
if (!drm_mode_expose_to_userspace(mode, file_priv))
continue;
drm_mode_convert_to_umode(&u_mode, mode);
- if (copy_to_user(mode_ptr + copied,
- &u_mode, sizeof(u_mode))) {
- ret = -EFAULT;
- mutex_unlock(&dev->mode_config.mutex);
+ if (user) {
+ if (copy_to_user(mode_ptr_user + copied,
+ &u_mode, sizeof(u_mode))) {
+ ret = -EFAULT;
+ mutex_unlock(&dev->mode_config.mutex);
- goto out;
+ goto out;
+ }
+ } else {
+ mode_ptr[copied] = u_mode;
}
copied++;
}
@@ -1656,6 +1667,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
return ret;
}
+int drm_mode_getconnector_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return drm_mode_getconnector(dev, data, file_priv, true);
+}
/**
* DOC: Tile group
@@ -538,21 +538,21 @@ EXPORT_SYMBOL(drm_crtc_check_viewport);
/**
* drm_mode_setcrtc - set CRTC configuration
* @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
+ * @crtc_req: pointer to request structure
+ * @file_priv: drm file
+ * @user: True if called form userspace, false from in-kernel client
*
- * Build a new CRTC configuration based on user request.
+ * Build a new CRTC configuration based on request.
*
- * Called by the user via ioctl.
+ * Called by the user via ioctl, or by an in-kernel client.
*
* Returns:
* Zero on success, negative errno on failure.
*/
-int drm_mode_setcrtc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+int drm_mode_setcrtc(struct drm_device *dev, struct drm_mode_crtc *crtc_req,
+ struct drm_file *file_priv, bool user)
{
struct drm_mode_config *config = &dev->mode_config;
- struct drm_mode_crtc *crtc_req = data;
struct drm_crtc *crtc;
struct drm_connector **connector_set = NULL, *connector;
struct drm_framebuffer *fb = NULL;
@@ -678,10 +678,14 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
for (i = 0; i < crtc_req->count_connectors; i++) {
connector_set[i] = NULL;
- set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
- if (get_user(out_id, &set_connectors_ptr[i])) {
- ret = -EFAULT;
- goto out;
+ if (user) {
+ set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
+ if (get_user(out_id, &set_connectors_ptr[i])) {
+ ret = -EFAULT;
+ goto out;
+ }
+ } else {
+ out_id = ((u32 *)(unsigned long)crtc_req->set_connectors_ptr)[i];
}
connector = drm_connector_lookup(dev, file_priv, out_id);
@@ -732,6 +736,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
return ret;
}
+int drm_mode_setcrtc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return drm_mode_setcrtc(dev, data, file_priv, true);
+}
+
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t value)
@@ -45,20 +45,26 @@ void drm_crtc_unregister_all(struct drm_device *dev);
struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc);
+int drm_mode_setcrtc(struct drm_device *dev, struct drm_mode_crtc *crtc_req,
+ struct drm_file *file_priv, bool user);
+
/* IOCTLs */
int drm_mode_getcrtc(struct drm_device *dev,
void *data, struct drm_file *file_priv);
-int drm_mode_setcrtc(struct drm_device *dev,
- void *data, struct drm_file *file_priv);
+int drm_mode_setcrtc_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
/* drm_mode_config.c */
int drm_modeset_register_all(struct drm_device *dev);
void drm_modeset_unregister_all(struct drm_device *dev);
+int drm_mode_getresources(struct drm_device *dev,
+ struct drm_mode_card_res *card_res,
+ struct drm_file *file_priv, bool user);
/* IOCTLs */
-int drm_mode_getresources(struct drm_device *dev,
- void *data, struct drm_file *file_priv);
+int drm_mode_getresources_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* drm_dumb_buffers.c */
@@ -143,12 +149,15 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
int drm_connector_create_standard_properties(struct drm_device *dev);
const char *drm_get_connector_force_name(enum drm_connector_force force);
void drm_connector_free_work_fn(struct work_struct *work);
+int drm_mode_getconnector(struct drm_device *dev,
+ struct drm_mode_get_connector *out_resp,
+ struct drm_file *file_priv, bool user);
/* IOCTL */
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
-int drm_mode_getconnector(struct drm_device *dev,
- void *data, struct drm_file *file_priv);
+int drm_mode_getconnector_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
/* drm_framebuffer.c */
struct drm_framebuffer *
@@ -161,6 +170,8 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
const struct drm_framebuffer *fb);
void drm_fb_release(struct drm_file *file_priv);
+int drm_mode_dirtyfb(struct drm_device *dev, struct drm_mode_fb_dirty_cmd *req,
+ struct drm_file *file_priv, bool user);
/* IOCTL */
int drm_mode_addfb(struct drm_device *dev,
@@ -486,10 +486,11 @@ int drm_mode_getfb(struct drm_device *dev,
}
/**
- * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
+ * drm_mode_dirtyfb - flush frontbuffer rendering on an FB
+ * @dev: drm device
+ * @r: pointer to request structure
+ * @file_priv: drm file
+ * @user: true if called form userspace, false if called by in-kernel client
*
* Lookup the FB and flush out the damaged area supplied by userspace as a clip
* rectangle list. Generic userspace which does frontbuffer rendering must call
@@ -499,17 +500,16 @@ int drm_mode_getfb(struct drm_device *dev,
* Modesetting drivers which always update the frontbuffer do not need to
* implement the corresponding &drm_framebuffer_funcs.dirty callback.
*
- * Called by the user via ioctl.
+ * Called by the user via ioctl, or by an in-kernel client.
*
* Returns:
* Zero on success, negative errno on failure.
*/
-int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
+int drm_mode_dirtyfb(struct drm_device *dev, struct drm_mode_fb_dirty_cmd *r,
+ struct drm_file *file_priv, bool user)
{
struct drm_clip_rect __user *clips_ptr;
struct drm_clip_rect *clips = NULL;
- struct drm_mode_fb_dirty_cmd *r = data;
struct drm_framebuffer *fb;
unsigned flags;
int num_clips;
@@ -523,9 +523,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
return -ENOENT;
num_clips = r->num_clips;
- clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
- if (!num_clips != !clips_ptr) {
+ if (!num_clips != !r->clips_ptr) {
ret = -EINVAL;
goto out_err1;
}
@@ -538,22 +537,28 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
goto out_err1;
}
- if (num_clips && clips_ptr) {
+ if (num_clips && r->clips_ptr) {
if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
ret = -EINVAL;
goto out_err1;
}
- clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
- if (!clips) {
- ret = -ENOMEM;
- goto out_err1;
- }
- ret = copy_from_user(clips, clips_ptr,
- num_clips * sizeof(*clips));
- if (ret) {
- ret = -EFAULT;
- goto out_err2;
+ if (user) {
+ clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
+ clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
+ if (!clips) {
+ ret = -ENOMEM;
+ goto out_err1;
+ }
+
+ ret = copy_from_user(clips, clips_ptr,
+ num_clips * sizeof(*clips));
+ if (ret) {
+ ret = -EFAULT;
+ goto out_err2;
+ }
+ } else {
+ clips = (struct drm_clip_rect *)(unsigned long)r->clips_ptr;
}
}
@@ -565,13 +570,20 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
}
out_err2:
- kfree(clips);
+ if (user)
+ kfree(clips);
out_err1:
drm_framebuffer_put(fb);
return ret;
}
+int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ return drm_mode_dirtyfb(dev, data, file_priv, true);
+}
+
/**
* drm_fb_release - remove and free the FBs on this file
* @priv: drm file for the ioctl
@@ -613,21 +613,21 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
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_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_SETCRTC, drm_mode_setcrtc_ioctl, 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_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),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
@@ -81,19 +81,20 @@ void drm_modeset_unregister_all(struct drm_device *dev)
* Returns:
* Zero on success, negative errno on failure.
*/
-int drm_mode_getresources(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+int drm_mode_getresources(struct drm_device *dev,
+ struct drm_mode_card_res *card_res,
+ struct drm_file *file_priv, bool user)
{
- struct drm_mode_card_res *card_res = data;
struct drm_framebuffer *fb;
struct drm_connector *connector;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int count, ret = 0;
- uint32_t __user *fb_id;
- uint32_t __user *crtc_id;
- uint32_t __user *connector_id;
- uint32_t __user *encoder_id;
+ uint32_t __user *fb_id_user;
+ uint32_t __user *crtc_id_user;
+ uint32_t __user *connector_id_user;
+ uint32_t __user *encoder_id_user;
+ u32 *fb_id, *crtc_id, *connector_id, *encoder_id;
struct drm_connector_list_iter conn_iter;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -102,12 +103,18 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
mutex_lock(&file_priv->fbs_lock);
count = 0;
- fb_id = u64_to_user_ptr(card_res->fb_id_ptr);
+ fb_id_user = u64_to_user_ptr(card_res->fb_id_ptr);
+ fb_id = (u32 *)(unsigned long)(card_res->fb_id_ptr);
list_for_each_entry(fb, &file_priv->fbs, filp_head) {
- if (count < card_res->count_fbs &&
- put_user(fb->base.id, fb_id + count)) {
- mutex_unlock(&file_priv->fbs_lock);
- return -EFAULT;
+ if (count < card_res->count_fbs) {
+ if (user) {
+ if (put_user(fb->base.id, fb_id_user + count)) {
+ mutex_unlock(&file_priv->fbs_lock);
+ return -EFAULT;
+ }
+ } else {
+ fb_id[count] = fb->base.id;
+ }
}
count++;
}
@@ -120,36 +127,54 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
card_res->min_width = dev->mode_config.min_width;
count = 0;
- crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
+ crtc_id_user = u64_to_user_ptr(card_res->crtc_id_ptr);
+ crtc_id = (u32 *)(unsigned long)(card_res->crtc_id_ptr);
drm_for_each_crtc(crtc, dev) {
if (drm_lease_held(file_priv, crtc->base.id)) {
- if (count < card_res->count_crtcs &&
- put_user(crtc->base.id, crtc_id + count))
- return -EFAULT;
+ if (count < card_res->count_crtcs) {
+ if (user) {
+ if (put_user(crtc->base.id, crtc_id_user + count))
+ return -EFAULT;
+ } else {
+ crtc_id[count] = crtc->base.id;
+ }
+ }
count++;
}
}
card_res->count_crtcs = count;
count = 0;
- encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
+ encoder_id_user = u64_to_user_ptr(card_res->encoder_id_ptr);
+ encoder_id = (u32 *)(unsigned long)(card_res->encoder_id_ptr);
drm_for_each_encoder(encoder, dev) {
- if (count < card_res->count_encoders &&
- put_user(encoder->base.id, encoder_id + count))
- return -EFAULT;
+ if (count < card_res->count_encoders) {
+ if (user) {
+ if (put_user(encoder->base.id, encoder_id_user + count))
+ return -EFAULT;
+ } else {
+ encoder_id[count] = encoder->base.id;
+ }
+ }
count++;
}
card_res->count_encoders = count;
drm_connector_list_iter_begin(dev, &conn_iter);
count = 0;
- connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
+ connector_id_user = u64_to_user_ptr(card_res->connector_id_ptr);
+ connector_id = (u32 *)(unsigned long)(card_res->connector_id_ptr);
drm_for_each_connector_iter(connector, &conn_iter) {
if (drm_lease_held(file_priv, connector->base.id)) {
- if (count < card_res->count_connectors &&
- put_user(connector->base.id, connector_id + count)) {
- drm_connector_list_iter_end(&conn_iter);
- return -EFAULT;
+ if (count < card_res->count_connectors) {
+ if (user) {
+ if (put_user(connector->base.id, connector_id_user + count)) {
+ drm_connector_list_iter_end(&conn_iter);
+ return -EFAULT;
+ }
+ } else {
+ connector_id[count] = connector->base.id;
+ }
}
count++;
}
@@ -160,6 +185,12 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
return ret;
}
+int drm_mode_getresources_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return drm_mode_getresources(dev, data, file_priv, true);
+}
+
/**
* drm_mode_config_reset - call ->reset callbacks
* @dev: drm device
This is part 1 of making ioctls useable for in-kernel clients. Make an ioctl wrapper function that calls a function that can be used by in-kernel clients. It adjusts the following functions to handle kernel buffers: - drm_mode_getresources() - drm_mode_setcrtc() - drm_mode_getconnector() - drm_mode_dirtyfb_ioctl() There is no functional change from the userspace side. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- drivers/gpu/drm/drm_connector.c | 50 +++++++++++++++-------- drivers/gpu/drm/drm_crtc.c | 32 ++++++++++----- drivers/gpu/drm/drm_crtc_internal.h | 23 ++++++++--- drivers/gpu/drm/drm_framebuffer.c | 56 +++++++++++++++---------- drivers/gpu/drm/drm_ioctl.c | 6 +-- drivers/gpu/drm/drm_mode_config.c | 81 +++++++++++++++++++++++++------------ 6 files changed, 164 insertions(+), 84 deletions(-)