int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_surface *surface = NULL; struct vmw_dma_buffer *dmabuf = NULL; int ret; if (handle) { ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, &surface); if (!ret) { if (!surface->snooper.image) { DRM_ERROR("surface not suitable for cursor\n"); return -EINVAL; } } else { ret = vmw_user_dmabuf_lookup(tfile, handle, &dmabuf); if (ret) { DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); return -EINVAL; } } } /* takedown old cursor */ if (du->cursor_surface) { du->cursor_surface->snooper.crtc = NULL; vmw_surface_unreference(&du->cursor_surface); } if (du->cursor_dmabuf) vmw_dmabuf_unreference(&du->cursor_dmabuf); /* setup new image */ if (surface) { /* vmw_user_surface_lookup takes one reference */ du->cursor_surface = surface; du->cursor_surface->snooper.crtc = crtc; du->cursor_age = du->cursor_surface->snooper.age; vmw_cursor_update_image(dev_priv, surface->snooper.image, 64, 64, du->hotspot_x, du->hotspot_y); } else if (dmabuf) { struct ttm_bo_kmap_obj map; unsigned long kmap_offset; unsigned long kmap_num; void *virtual; bool dummy; /* vmw_user_surface_lookup takes one reference */ du->cursor_dmabuf = dmabuf; kmap_offset = 0; kmap_num = (64*64*4) >> PAGE_SHIFT; ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); if (unlikely(ret != 0)) { DRM_ERROR("reserve failed\n"); return -EINVAL; } ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); if (unlikely(ret != 0)) goto err_unreserve; virtual = ttm_kmap_obj_virtual(&map, &dummy); vmw_cursor_update_image(dev_priv, virtual, 64, 64, du->hotspot_x, du->hotspot_y); ttm_bo_kunmap(&map); err_unreserve: ttm_bo_unreserve(&dmabuf->base); } else {
int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_present_arg *arg = (struct drm_vmw_present_arg *)data; struct vmw_surface *surface; struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_mode_object *obj; struct vmw_framebuffer *vfb; uint32_t num_clips; int ret; num_clips = arg->num_clips; clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; if (unlikely(num_clips == 0)) return 0; if (clips_ptr == NULL) { DRM_ERROR("Variable clips_ptr must be specified.\n"); ret = -EINVAL; goto out_clips; } clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (clips == NULL) { DRM_ERROR("Failed to allocate clip rect list.\n"); ret = -ENOMEM; goto out_clips; } ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); if (ret) { DRM_ERROR("Failed to copy clip rects from userspace.\n"); ret = -EFAULT; goto out_no_copy; } ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (unlikely(ret != 0)) { ret = -ERESTARTSYS; goto out_no_mode_mutex; } obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { DRM_ERROR("Invalid framebuffer id.\n"); ret = -EINVAL; goto out_no_fb; } vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) goto out_no_ttm_lock; ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid, &surface); if (ret) goto out_no_surface; ret = vmw_kms_present(dev_priv, file_priv, vfb, surface, arg->sid, arg->dest_x, arg->dest_y, clips, num_clips); /* vmw_user_surface_lookup takes one ref so does new_fb */ vmw_surface_unreference(&surface); out_no_surface: ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: out_no_fb: mutex_unlock(&dev->mode_config.mutex); out_no_mode_mutex: out_no_copy: kfree(clips); out_clips: return ret; }