diff options
Diffstat (limited to 'bsd-core/drm_drawable.c')
-rw-r--r-- | bsd-core/drm_drawable.c | 113 |
1 files changed, 105 insertions, 8 deletions
diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c index 379e0aa7..7e038ab9 100644 --- a/bsd-core/drm_drawable.c +++ b/bsd-core/drm_drawable.c @@ -33,19 +33,116 @@ #include "drmP.h" -int drm_adddraw(DRM_IOCTL_ARGS) +struct bsd_drm_drawable_info { + struct drm_drawable_info info; + int handle; + RB_ENTRY(bsd_drm_drawable_info) tree; +}; + +static int +drm_drawable_compare(struct bsd_drm_drawable_info *a, + struct bsd_drm_drawable_info *b) +{ + if (a->handle > b->handle) + return 1; + if (a->handle < b->handle) + return -1; + return 0; +} + +RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree, + drm_drawable_compare); + +struct drm_drawable_info * +drm_get_drawable_info(drm_device_t *dev, int handle) { - drm_draw_t draw; + struct bsd_drm_drawable_info find, *result; + + find.handle = handle; + result = RB_FIND(drawable_tree, &dev->drw_head, &find); - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) ); + return &result->info; +} + +int drm_adddraw(drm_device_t *dev, void *data, struct drm_file *file_priv) +{ + drm_draw_t *draw = data; + struct bsd_drm_drawable_info *info; + + info = drm_calloc(1, sizeof(struct bsd_drm_drawable_info), + DRM_MEM_DRAWABLE); + if (info == NULL) + return ENOMEM; + + info->handle = alloc_unr(dev->drw_unrhdr); + DRM_SPINLOCK(&dev->drw_lock); + RB_INSERT(drawable_tree, &dev->drw_head, info); + draw->handle = info->handle; + DRM_SPINUNLOCK(&dev->drw_lock); + + DRM_DEBUG("%d\n", draw->handle); return 0; } -int drm_rmdraw(DRM_IOCTL_ARGS) +int drm_rmdraw(drm_device_t *dev, void *data, struct drm_file *file_priv) { - return 0; /* NOOP */ + drm_draw_t *draw = (drm_draw_t *)data; + struct drm_drawable_info *info; + + DRM_SPINLOCK(&dev->drw_lock); + info = drm_get_drawable_info(dev, draw->handle); + if (info != NULL) { + RB_REMOVE(drawable_tree, &dev->drw_head, + (struct bsd_drm_drawable_info *)info); + DRM_SPINUNLOCK(&dev->drw_lock); + free_unr(dev->drw_unrhdr, draw->handle); + drm_free(info, sizeof(struct bsd_drm_drawable_info), + DRM_MEM_DRAWABLE); + return 0; + } else { + DRM_SPINUNLOCK(&dev->drw_lock); + return EINVAL; + } +} + +int drm_update_draw(drm_device_t *dev, void *data, struct drm_file *file_priv) +{ + struct drm_drawable_info *info; + struct drm_update_draw *update = (struct drm_update_draw *)data; + int ret; + + info = drm_get_drawable_info(dev, update->handle); + if (info == NULL) + return EINVAL; + + switch (update->type) { + case DRM_DRAWABLE_CLIPRECTS: + DRM_SPINLOCK(&dev->drw_lock); + if (update->num != info->num_rects) { + drm_free(info->rects, + sizeof(*info->rects) * info->num_rects, + DRM_MEM_DRAWABLE); + info->rects = NULL; + info->num_rects = 0; + } + if (update->num == 0) { + DRM_SPINUNLOCK(&dev->drw_lock); + return 0; + } + if (info->rects == NULL) { + info->rects = drm_alloc(sizeof(*info->rects) * + update->num, DRM_MEM_DRAWABLE); + if (info->rects == NULL) + return ENOMEM; + info->num_rects = update->num; + } + /* For some reason the pointer arg is unsigned long long. */ + ret = copyin((void *)(intptr_t)update->data, info->rects, + sizeof(*info->rects) * info->num_rects); + DRM_SPINUNLOCK(&dev->drw_lock); + return ret; + default: + return EINVAL; + } } |