diff options
author | Jonathan Gray <jsg@jsg.id.au> | 2012-11-17 15:58:47 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@jsg.id.au> | 2013-01-10 12:22:00 +1100 |
commit | 4dc74b09dc0e39cdd1e9cc4a1ad4d70e3f6f5c82 (patch) | |
tree | ffcc508cb3ee5f762803b2e29767d0c31985869e /sys/dev | |
parent | c52496b423a16cffb5b1300b1104afca2a378723 (diff) |
add plane ioctls
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/drm/drm_crtc.c | 250 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_crtc.h | 10 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_drv.c | 6 |
3 files changed, 264 insertions, 2 deletions
diff --git a/sys/dev/pci/drm/drm_crtc.c b/sys/dev/pci/drm/drm_crtc.c index d8488cf45ed..ba209568a89 100644 --- a/sys/dev/pci/drm/drm_crtc.c +++ b/sys/dev/pci/drm/drm_crtc.c @@ -1557,6 +1557,256 @@ out: } /** + * drm_mode_getplane_res - get plane info + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * LOCKING: + * Takes mode config lock. + * + * Return an plane count and set of IDs. + */ +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane_res *plane_resp = data; + struct drm_mode_config *config; + struct drm_plane *plane; + uint32_t *plane_ptr; + int copied = 0, ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return (EINVAL); + + // mutex_lock(&dev->mode_config.mutex); + config = &dev->mode_config; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (config->num_plane && + (plane_resp->count_planes >= config->num_plane)) { + plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; + + TAILQ_FOREACH(plane, &config->plane_list, head) { + if (copyout(&plane->base.id, plane_ptr + copied, + sizeof(uint32_t))) { + ret = EFAULT; + goto out; + } + copied++; + } + } + plane_resp->count_planes = config->num_plane; + +out: + // mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_getplane - get plane info + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * LOCKING: + * Takes mode config lock. + * + * Return plane info, including formats supported, gamma size, any + * current fb, etc. + */ +int drm_mode_getplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane *plane_resp = data; + struct drm_mode_object *obj; + struct drm_plane *plane; + uint32_t *format_ptr; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return (EINVAL); + + // mutex_lock(&dev->mode_config.mutex); + obj = drm_mode_object_find(dev, plane_resp->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!obj) { + ret = ENOENT; + goto out; + } + plane = obj_to_plane(obj); + + if (plane->crtc) + plane_resp->crtc_id = plane->crtc->base.id; + else + plane_resp->crtc_id = 0; + + if (plane->fb) + plane_resp->fb_id = plane->fb->base.id; + else + plane_resp->fb_id = 0; + + plane_resp->plane_id = plane->base.id; + plane_resp->possible_crtcs = plane->possible_crtcs; + plane_resp->gamma_size = plane->gamma_size; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (plane->format_count && + (plane_resp->count_format_types >= plane->format_count)) { + format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; + if (copyout(format_ptr, + plane->format_types, + sizeof(uint32_t) * plane->format_count)) { + ret = EFAULT; + goto out; + } + } + plane_resp->count_format_types = plane->format_count; + +out: + // mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_setplane - set up or tear down an plane + * @dev: DRM device + * @data: ioctl data* + * @file_prive: DRM file info + * + * LOCKING: + * Takes mode config lock. + * + * Set plane info, including placement, fb, scaling, and other factors. + * Or pass a NULL fb to disable. + */ +int drm_mode_setplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_set_plane *plane_req = data; + struct drm_mode_object *obj; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_framebuffer *fb; + int ret = 0; + unsigned int fb_width, fb_height; + int i; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return (EINVAL); + + // mutex_lock(&dev->mode_config.mutex); + + /* + * First, find the plane, crtc, and fb objects. If not available, + * we don't bother to call the driver. + */ + obj = drm_mode_object_find(dev, plane_req->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!obj) { + DRM_DEBUG_KMS("Unknown plane ID %d\n", + plane_req->plane_id); + ret = ENOENT; + goto out; + } + plane = obj_to_plane(obj); + + /* No fb means shut it down */ + if (!plane_req->fb_id) { + plane->funcs->disable_plane(plane); + plane->crtc = NULL; + plane->fb = NULL; + goto out; + } + + obj = drm_mode_object_find(dev, plane_req->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_DEBUG_KMS("Unknown crtc ID %d\n", + plane_req->crtc_id); + ret = ENOENT; + goto out; + } + crtc = obj_to_crtc(obj); + + obj = drm_mode_object_find(dev, plane_req->fb_id, + DRM_MODE_OBJECT_FB); + if (!obj) { + DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", + plane_req->fb_id); + ret = ENOENT; + goto out; + } + fb = obj_to_fb(obj); + + /* Check whether this plane supports the fb pixel format. */ + for (i = 0; i < plane->format_count; i++) + if (fb->pixel_format == plane->format_types[i]) + break; + if (i == plane->format_count) { + DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); + ret = EINVAL; + goto out; + } + + fb_width = fb->width << 16; + fb_height = fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (plane_req->src_w > fb_width || + plane_req->src_x > fb_width - plane_req->src_w || + plane_req->src_h > fb_height || + plane_req->src_y > fb_height - plane_req->src_h) { + DRM_DEBUG_KMS("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + plane_req->src_w >> 16, + ((plane_req->src_w & 0xffff) * 15625) >> 10, + plane_req->src_h >> 16, + ((plane_req->src_h & 0xffff) * 15625) >> 10, + plane_req->src_x >> 16, + ((plane_req->src_x & 0xffff) * 15625) >> 10, + plane_req->src_y >> 16, + ((plane_req->src_y & 0xffff) * 15625) >> 10); + ret = ENOSPC; + goto out; + } + + /* Give drivers some help against integer overflows */ + if (plane_req->crtc_w > INT_MAX || + plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || + plane_req->crtc_h > INT_MAX || + plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + plane_req->crtc_w, plane_req->crtc_h, + plane_req->crtc_x, plane_req->crtc_y); + ret = ERANGE; + goto out; + } + + ret = -plane->funcs->update_plane(plane, crtc, fb, + plane_req->crtc_x, plane_req->crtc_y, + plane_req->crtc_w, plane_req->crtc_h, + plane_req->src_x, plane_req->src_y, + plane_req->src_w, plane_req->src_h); + if (!ret) { + plane->crtc = crtc; + plane->fb = fb; + } + +out: + // mutex_unlock(&dev->mode_config.mutex); + + return ret; +} + + +/** * drm_mode_setcrtc - set CRTC configuration * @inode: inode from the ioctl * @filp: file * from the ioctl diff --git a/sys/dev/pci/drm/drm_crtc.h b/sys/dev/pci/drm/drm_crtc.h index 6ef7eb40111..f7d421a1cfa 100644 --- a/sys/dev/pci/drm/drm_crtc.h +++ b/sys/dev/pci/drm/drm_crtc.h @@ -245,6 +245,7 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; + uint32_t pixel_format; /* fourcc format */ TAILQ_ENTRY(drm_framebuffer) filp_head; /* if you are using the helper */ void *helper_private; @@ -700,7 +701,7 @@ struct drm_mode_config { #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) #define obj_to_property(x) container_of(x, struct drm_property, base) #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) - +#define obj_to_plane(x) container_of(x, struct drm_plane, base) extern void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, @@ -819,13 +820,18 @@ extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); - +extern int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_setplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_addfb(struct drm_device *dev, diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c index ab097dcd9b5..e2ff2c73ce8 100644 --- a/sys/dev/pci/drm/drm_drv.c +++ b/sys/dev/pci/drm/drm_drv.c @@ -708,10 +708,16 @@ drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags, return (EBUSY); case DRM_IOCTL_MODE_GETRESOURCES: return drm_mode_getresources(dev, data, file_priv); + case DRM_IOCTL_MODE_GETPLANERESOURCES: + return drm_mode_getplane_res(dev, data, file_priv); case DRM_IOCTL_MODE_GETCRTC: return drm_mode_getcrtc(dev, data, file_priv); case DRM_IOCTL_MODE_SETCRTC: return drm_mode_setcrtc(dev, data, file_priv); + case DRM_IOCTL_MODE_GETPLANE: + return drm_mode_getplane(dev, data, file_priv); + case DRM_IOCTL_MODE_SETPLANE: + return drm_mode_setplane(dev, data, file_priv); case DRM_IOCTL_MODE_CURSOR: return drm_mode_cursor_ioctl(dev, data, file_priv); case DRM_IOCTL_MODE_GETGAMMA: |