linux/drivers/gpu/drm/drm_drawable.c
<<
>>
Prefs
   1/**
   2 * \file drm_drawable.c
   3 * IOCTLs for drawables
   4 *
   5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
   6 * \author Gareth Hughes <gareth@valinux.com>
   7 * \author Michel Dänzer <michel@tungstengraphics.com>
   8 */
   9
  10/*
  11 * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
  12 *
  13 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  14 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  15 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
  16 * All Rights Reserved.
  17 *
  18 * Permission is hereby granted, free of charge, to any person obtaining a
  19 * copy of this software and associated documentation files (the "Software"),
  20 * to deal in the Software without restriction, including without limitation
  21 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  22 * and/or sell copies of the Software, and to permit persons to whom the
  23 * Software is furnished to do so, subject to the following conditions:
  24 *
  25 * The above copyright notice and this permission notice (including the next
  26 * paragraph) shall be included in all copies or substantial portions of the
  27 * Software.
  28 *
  29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  32 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  33 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  34 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  35 * OTHER DEALINGS IN THE SOFTWARE.
  36 */
  37
  38#include "drmP.h"
  39
  40/**
  41 * Allocate drawable ID and memory to store information about it.
  42 */
  43int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
  44{
  45        unsigned long irqflags;
  46        struct drm_draw *draw = data;
  47        int new_id = 0;
  48        int ret;
  49
  50again:
  51        if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
  52                DRM_ERROR("Out of memory expanding drawable idr\n");
  53                return -ENOMEM;
  54        }
  55
  56        spin_lock_irqsave(&dev->drw_lock, irqflags);
  57        ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
  58        if (ret == -EAGAIN) {
  59                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
  60                goto again;
  61        }
  62
  63        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
  64
  65        draw->handle = new_id;
  66
  67        DRM_DEBUG("%d\n", draw->handle);
  68
  69        return 0;
  70}
  71
  72/**
  73 * Free drawable ID and memory to store information about it.
  74 */
  75int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
  76{
  77        struct drm_draw *draw = data;
  78        unsigned long irqflags;
  79        struct drm_drawable_info *info;
  80
  81        spin_lock_irqsave(&dev->drw_lock, irqflags);
  82
  83        info = drm_get_drawable_info(dev, draw->handle);
  84        if (info == NULL) {
  85                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
  86                return -EINVAL;
  87        }
  88        kfree(info->rects);
  89        kfree(info);
  90
  91        idr_remove(&dev->drw_idr, draw->handle);
  92
  93        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
  94        DRM_DEBUG("%d\n", draw->handle);
  95        return 0;
  96}
  97
  98int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
  99{
 100        struct drm_update_draw *update = data;
 101        unsigned long irqflags;
 102        struct drm_clip_rect *rects;
 103        struct drm_drawable_info *info;
 104        int err;
 105
 106        info = idr_find(&dev->drw_idr, update->handle);
 107        if (!info) {
 108                info = kzalloc(sizeof(*info), GFP_KERNEL);
 109                if (!info)
 110                        return -ENOMEM;
 111                if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
 112                        DRM_ERROR("No such drawable %d\n", update->handle);
 113                        kfree(info);
 114                        return -EINVAL;
 115                }
 116        }
 117
 118        switch (update->type) {
 119        case DRM_DRAWABLE_CLIPRECTS:
 120                if (update->num == 0)
 121                        rects = NULL;
 122                else if (update->num != info->num_rects) {
 123                        rects = kmalloc(update->num *
 124                                        sizeof(struct drm_clip_rect),
 125                                        GFP_KERNEL);
 126                } else
 127                        rects = info->rects;
 128
 129                if (update->num && !rects) {
 130                        DRM_ERROR("Failed to allocate cliprect memory\n");
 131                        err = -ENOMEM;
 132                        goto error;
 133                }
 134
 135                if (update->num && DRM_COPY_FROM_USER(rects,
 136                                                     (struct drm_clip_rect __user *)
 137                                                     (unsigned long)update->data,
 138                                                     update->num *
 139                                                     sizeof(*rects))) {
 140                        DRM_ERROR("Failed to copy cliprects from userspace\n");
 141                        err = -EFAULT;
 142                        goto error;
 143                }
 144
 145                spin_lock_irqsave(&dev->drw_lock, irqflags);
 146
 147                if (rects != info->rects) {
 148                        kfree(info->rects);
 149                }
 150
 151                info->rects = rects;
 152                info->num_rects = update->num;
 153
 154                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 155
 156                DRM_DEBUG("Updated %d cliprects for drawable %d\n",
 157                          info->num_rects, update->handle);
 158                break;
 159        default:
 160                DRM_ERROR("Invalid update type %d\n", update->type);
 161                return -EINVAL;
 162        }
 163
 164        return 0;
 165
 166error:
 167        if (rects != info->rects)
 168                kfree(rects);
 169
 170        return err;
 171}
 172
 173/**
 174 * Caller must hold the drawable spinlock!
 175 */
 176struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
 177{
 178        return idr_find(&dev->drw_idr, id);
 179}
 180EXPORT_SYMBOL(drm_get_drawable_info);
 181
 182static int drm_drawable_free(int idr, void *p, void *data)
 183{
 184        struct drm_drawable_info *info = p;
 185
 186        if (info) {
 187                kfree(info->rects);
 188                kfree(info);
 189        }
 190
 191        return 0;
 192}
 193
 194void drm_drawable_free_all(struct drm_device *dev)
 195{
 196        idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
 197        idr_remove_all(&dev->drw_idr);
 198}
 199