diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 153 |
1 files changed, 98 insertions, 55 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index bff2fa9..d6cf77c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -202,6 +202,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_TV, "TV" }, { DRM_MODE_CONNECTOR_eDP, "eDP" }, { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, + { DRM_MODE_CONNECTOR_DSI, "DSI" }, }; static const struct drm_prop_enum_list drm_encoder_enum_list[] = @@ -211,6 +212,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_LVDS, "LVDS" }, { DRM_MODE_ENCODER_TVDAC, "TV" }, { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, + { DRM_MODE_ENCODER_DSI, "DSI" }, }; void drm_connector_ida_init(void) @@ -1301,7 +1303,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, } /** - * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode + * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode * @out: drm_display_mode to return to the user * @in: drm_mode_modeinfo to use * @@ -1317,6 +1319,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, if (in->clock > INT_MAX || in->vrefresh > INT_MAX) return -ERANGE; + if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) + return -EINVAL; + out->clock = in->clock; out->hdisplay = in->hdisplay; out->hsync_start = in->hsync_start; @@ -1552,7 +1557,7 @@ int drm_mode_getcrtc(struct drm_device *dev, obj = drm_mode_object_find(dev, crtc_resp->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } crtc = obj_to_crtc(obj); @@ -1579,6 +1584,19 @@ out: return ret; } +static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, + const struct drm_file *file_priv) +{ + /* + * If user-space hasn't configured the driver to expose the stereo 3D + * modes, don't expose them. + */ + if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) + return false; + + return true; +} + /** * drm_mode_getconnector - get connector configuration * @dev: drm device for the ioctl @@ -1623,7 +1641,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } connector = obj_to_connector(obj); @@ -1644,7 +1662,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, /* delayed so we get modes regardless of pre-fill_modes state */ list_for_each_entry(mode, &connector->modes, head) - mode_count++; + if (drm_mode_expose_to_userspace(mode, file_priv)) + mode_count++; out_resp->connector_id = connector->base.id; out_resp->connector_type = connector->connector_type; @@ -1666,6 +1685,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, copied = 0; mode_ptr = (struct drm_mode_modeinfo __user *)(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_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(mode_ptr + copied, &u_mode, sizeof(u_mode))) { @@ -1735,7 +1757,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } encoder = obj_to_encoder(obj); @@ -2040,6 +2062,45 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) } EXPORT_SYMBOL(drm_mode_set_config_internal); +/* + * Checks that the framebuffer is big enough for the CRTC viewport + * (x, y, hdisplay, vdisplay) + */ +static int drm_crtc_check_viewport(const struct drm_crtc *crtc, + int x, int y, + const struct drm_display_mode *mode, + const struct drm_framebuffer *fb) + +{ + int hdisplay, vdisplay; + + hdisplay = mode->hdisplay; + vdisplay = mode->vdisplay; + + if (drm_mode_is_stereo(mode)) { + struct drm_display_mode adjusted = *mode; + + drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); + hdisplay = adjusted.crtc_hdisplay; + vdisplay = adjusted.crtc_vdisplay; + } + + if (crtc->invert_dimensions) + swap(hdisplay, vdisplay); + + if (hdisplay > fb->width || + vdisplay > fb->height || + x > fb->width - hdisplay || + y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, hdisplay, vdisplay, x, y, + crtc->invert_dimensions ? " (inverted)" : ""); + return -ENOSPC; + } + + return 0; +} + /** * drm_mode_setcrtc - set CRTC configuration * @dev: drm device for the ioctl @@ -2080,14 +2141,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); - ret = -EINVAL; + ret = -ENOENT; goto out; } crtc = obj_to_crtc(obj); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (crtc_req->mode_valid) { - int hdisplay, vdisplay; /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ if (crtc_req->fb_id == -1) { @@ -2104,7 +2164,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (!fb) { DRM_DEBUG_KMS("Unknown FB ID%d\n", crtc_req->fb_id); - ret = -EINVAL; + ret = -ENOENT; goto out; } } @@ -2123,23 +2183,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - hdisplay = mode->hdisplay; - vdisplay = mode->vdisplay; - - if (crtc->invert_dimensions) - swap(hdisplay, vdisplay); - - if (hdisplay > fb->width || - vdisplay > fb->height || - crtc_req->x > fb->width - hdisplay || - crtc_req->y > fb->height - vdisplay) { - DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", - fb->width, fb->height, - hdisplay, vdisplay, crtc_req->x, crtc_req->y, - crtc->invert_dimensions ? " (inverted)" : ""); - ret = -ENOSPC; + ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, + mode, fb); + if (ret) goto out; - } + } if (crtc_req->count_connectors == 0 && mode) { @@ -2184,7 +2232,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Connector id %d unknown\n", out_id); - ret = -EINVAL; + ret = -ENOENT; goto out; } connector = obj_to_connector(obj); @@ -2232,7 +2280,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); - return -EINVAL; + return -ENOENT; } crtc = obj_to_crtc(obj); @@ -2441,6 +2489,8 @@ static int format_check(const struct drm_mode_fb_cmd2 *r) case DRM_FORMAT_YVU444: return 0; default: + DRM_DEBUG_KMS("invalid pixel format %s\n", + drm_get_format_name(r->pixel_format)); return -EINVAL; } } @@ -2606,7 +2656,7 @@ fail_lookup: mutex_unlock(&dev->mode_config.fb_lock); mutex_unlock(&file_priv->fbs_lock); - return -EINVAL; + return -ENOENT; } /** @@ -2634,7 +2684,7 @@ int drm_mode_getfb(struct drm_device *dev, fb = drm_framebuffer_lookup(dev, r->fb_id); if (!fb) - return -EINVAL; + return -ENOENT; r->height = fb->height; r->width = fb->width; @@ -2679,7 +2729,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, fb = drm_framebuffer_lookup(dev, r->fb_id); if (!fb) - return -EINVAL; + return -ENOENT; num_clips = r->num_clips; clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; @@ -3011,7 +3061,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto done; } property = obj_to_property(obj); @@ -3140,7 +3190,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto done; } blob = obj_to_blob(obj); @@ -3301,7 +3351,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } if (!obj->properties) { @@ -3354,8 +3404,10 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, drm_modeset_lock_all(dev); arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); - if (!arg_obj) + if (!arg_obj) { + ret = -ENOENT; goto out; + } if (!arg_obj->properties) goto out; @@ -3368,8 +3420,10 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, prop_obj = drm_mode_object_find(dev, arg->prop_id, DRM_MODE_OBJECT_PROPERTY); - if (!prop_obj) + if (!prop_obj) { + ret = -ENOENT; goto out; + } property = obj_to_property(prop_obj); if (!drm_property_change_is_valid(property, arg->value)) @@ -3454,7 +3508,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } crtc = obj_to_crtc(obj); @@ -3513,7 +3567,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - ret = -EINVAL; + ret = -ENOENT; goto out; } crtc = obj_to_crtc(obj); @@ -3556,7 +3610,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_framebuffer *fb = NULL, *old_fb = NULL; struct drm_pending_vblank_event *e = NULL; unsigned long flags; - int hdisplay, vdisplay; int ret = -EINVAL; if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || @@ -3568,7 +3621,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) - return -EINVAL; + return -ENOENT; crtc = obj_to_crtc(obj); mutex_lock(&crtc->mutex); @@ -3585,25 +3638,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out; fb = drm_framebuffer_lookup(dev, page_flip->fb_id); - if (!fb) + if (!fb) { + ret = -ENOENT; goto out; + } - hdisplay = crtc->mode.hdisplay; - vdisplay = crtc->mode.vdisplay; - - if (crtc->invert_dimensions) - swap(hdisplay, vdisplay); - - if (hdisplay > fb->width || - vdisplay > fb->height || - crtc->x > fb->width - hdisplay || - crtc->y > fb->height - vdisplay) { - DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", - fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y, - crtc->invert_dimensions ? " (inverted)" : ""); - ret = -ENOSPC; + ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); + if (ret) goto out; - } if (crtc->fb->pixel_format != fb->pixel_format) { DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); @@ -3788,7 +3830,8 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, *bpp = 32; break; default: - DRM_DEBUG_KMS("unsupported pixel format\n"); + DRM_DEBUG_KMS("unsupported pixel format %s\n", + drm_get_format_name(format)); *depth = 0; *bpp = 0; break; |