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(DRM_IOCTL_ARGS) 44{ 45 DRM_DEVICE; 46 unsigned long irqflags; 47 int i, j; 48 u32 *bitfield = dev->drw_bitfield; 49 unsigned int bitfield_length = dev->drw_bitfield_length; 50 drm_drawable_info_t **info = dev->drw_info; 51 unsigned int info_length = dev->drw_info_length; 52 drm_draw_t draw; 53 54 for (i = 0, j = 0; i < bitfield_length; i++) { 55 if (bitfield[i] == ~0) 56 continue; 57 58 for (; j < 8 * sizeof(*bitfield); j++) 59 if (!(bitfield[i] & (1 << j))) 60 goto done; 61 } 62done: 63 64 if (i == bitfield_length) { 65 bitfield_length++; 66 67 bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), 68 DRM_MEM_BUFS); 69 70 if (!bitfield) { 71 DRM_ERROR("Failed to allocate new drawable bitfield\n"); 72 return DRM_ERR(ENOMEM); 73 } 74 75 if (8 * sizeof(*bitfield) * bitfield_length > info_length) { 76 info_length += 8 * sizeof(*bitfield); 77 78 info = drm_alloc(info_length * sizeof(*info), 79 DRM_MEM_BUFS); 80 81 if (!info) { 82 DRM_ERROR("Failed to allocate new drawable info" 83 " array\n"); 84 85 drm_free(bitfield, 86 bitfield_length * sizeof(*bitfield), 87 DRM_MEM_BUFS); 88 return DRM_ERR(ENOMEM); 89 } 90 } 91 92 bitfield[i] = 0; 93 } 94 95 draw.handle = i * 8 * sizeof(*bitfield) + j + 1; 96 DRM_DEBUG("%d\n", draw.handle); 97 98 spin_lock_irqsave(&dev->drw_lock, irqflags); 99 100 bitfield[i] |= 1 << j; 101 info[draw.handle - 1] = NULL; 102 103 if (bitfield != dev->drw_bitfield) { 104 memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * 105 sizeof(*bitfield)); 106 drm_free(dev->drw_bitfield, sizeof(*bitfield) * 107 dev->drw_bitfield_length, DRM_MEM_BUFS); 108 dev->drw_bitfield = bitfield; 109 dev->drw_bitfield_length = bitfield_length; 110 } 111 112 if (info != dev->drw_info) { 113 memcpy(info, dev->drw_info, dev->drw_info_length * 114 sizeof(*info)); 115 drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, 116 DRM_MEM_BUFS); 117 dev->drw_info = info; 118 dev->drw_info_length = info_length; 119 } 120 121 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 122 123 DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); 124 125 return 0; 126} 127 128/** 129 * Free drawable ID and memory to store information about it. 130 */ 131int drm_rmdraw(DRM_IOCTL_ARGS) 132{ 133 DRM_DEVICE; 134 drm_draw_t draw; 135 int id, idx; 136 unsigned int shift; 137 unsigned long irqflags; 138 u32 *bitfield = dev->drw_bitfield; 139 unsigned int bitfield_length = dev->drw_bitfield_length; 140 drm_drawable_info_t **info = dev->drw_info; 141 unsigned int info_length = dev->drw_info_length; 142 143 DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, 144 sizeof(draw)); 145 146 id = draw.handle - 1; 147 idx = id / (8 * sizeof(*bitfield)); 148 shift = id % (8 * sizeof(*bitfield)); 149 150 if (idx < 0 || idx >= bitfield_length || 151 !(bitfield[idx] & (1 << shift))) { 152 DRM_DEBUG("No such drawable %d\n", draw.handle); 153 return 0; 154 } 155 156 spin_lock_irqsave(&dev->drw_lock, irqflags); 157 158 bitfield[idx] &= ~(1 << shift); 159 160 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 161 162 if (info[id]) { 163 drm_free(info[id]->rects, info[id]->num_rects * 164 sizeof(drm_clip_rect_t), DRM_MEM_BUFS); 165 drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); 166 } 167 168 /* Can we shrink the arrays? */ 169 if (idx == bitfield_length - 1) { 170 while (idx >= 0 && !bitfield[idx]) 171 --idx; 172 173 bitfield_length = idx + 1; 174 175 bitfield = NULL; 176 177 if (bitfield_length) { 178 if (bitfield_length != dev->drw_bitfield_length) 179 bitfield = drm_alloc(bitfield_length * 180 sizeof(*bitfield), 181 DRM_MEM_BUFS); 182 183 if (!bitfield) { 184 bitfield = dev->drw_bitfield; 185 bitfield_length = dev->drw_bitfield_length; 186 } 187 } 188 } 189 190 if (bitfield != dev->drw_bitfield) { 191 info_length = 8 * sizeof(*bitfield) * bitfield_length; 192 193 if (info_length) { 194 info = drm_alloc(info_length * sizeof(*info), 195 DRM_MEM_BUFS); 196 197 if (!info) { 198 info = dev->drw_info; 199 info_length = dev->drw_info_length; 200 } 201 } else 202 info = NULL; 203 204 spin_lock_irqsave(&dev->drw_lock, irqflags); 205 206 if (bitfield) 207 memcpy(bitfield, dev->drw_bitfield, bitfield_length * 208 sizeof(*bitfield)); 209 drm_free(dev->drw_bitfield, sizeof(*bitfield) * 210 dev->drw_bitfield_length, DRM_MEM_BUFS); 211 dev->drw_bitfield = bitfield; 212 dev->drw_bitfield_length = bitfield_length; 213 214 if (info != dev->drw_info) { 215 if (info) 216 memcpy(info, dev->drw_info, info_length * 217 sizeof(*info)); 218 drm_free(dev->drw_info, sizeof(*info) * 219 dev->drw_info_length, DRM_MEM_BUFS); 220 dev->drw_info = info; 221 dev->drw_info_length = info_length; 222 } 223 224 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 225 } 226 227 DRM_DEBUG("%d\n", draw.handle); 228 return 0; 229} 230 231int drm_update_drawable_info(DRM_IOCTL_ARGS) { 232 DRM_DEVICE; 233 drm_update_draw_t update; 234 unsigned int id, idx, shift; 235 u32 *bitfield = dev->drw_bitfield; 236 unsigned long irqflags, bitfield_length = dev->drw_bitfield_length; 237 drm_drawable_info_t *info; 238 drm_clip_rect_t *rects; 239 int err; 240 241 DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, 242 sizeof(update)); 243 244 id = update.handle - 1; 245 idx = id / (8 * sizeof(*bitfield)); 246 shift = id % (8 * sizeof(*bitfield)); 247 248 if (idx < 0 || idx >= bitfield_length || 249 !(bitfield[idx] & (1 << shift))) { 250 DRM_ERROR("No such drawable %d\n", update.handle); 251 return DRM_ERR(EINVAL); 252 } 253 254 info = dev->drw_info[id]; 255 256 if (!info) { 257 info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); 258 259 if (!info) { 260 DRM_ERROR("Failed to allocate drawable info memory\n"); 261 return DRM_ERR(ENOMEM); 262 } 263 } 264 265 switch (update.type) { 266 case DRM_DRAWABLE_CLIPRECTS: 267 if (update.num != info->num_rects) { 268 rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), 269 DRM_MEM_BUFS); 270 } else 271 rects = info->rects; 272 273 if (update.num && !rects) { 274 DRM_ERROR("Failed to allocate cliprect memory\n"); 275 err = DRM_ERR(ENOMEM); 276 goto error; 277 } 278 279 if (update.num && DRM_COPY_FROM_USER(rects, 280 (drm_clip_rect_t __user *) 281 (unsigned long)update.data, 282 update.num * 283 sizeof(*rects))) { 284 DRM_ERROR("Failed to copy cliprects from userspace\n"); 285 err = DRM_ERR(EFAULT); 286 goto error; 287 } 288 289 spin_lock_irqsave(&dev->drw_lock, irqflags); 290 291 if (rects != info->rects) { 292 drm_free(info->rects, info->num_rects * 293 sizeof(drm_clip_rect_t), DRM_MEM_BUFS); 294 } 295 296 info->rects = rects; 297 info->num_rects = update.num; 298 dev->drw_info[id] = info; 299 300 spin_unlock_irqrestore(&dev->drw_lock, irqflags); 301 302 DRM_DEBUG("Updated %d cliprects for drawable %d\n", 303 info->num_rects, id); 304 break; 305 default: 306 DRM_ERROR("Invalid update type %d\n", update.type); 307 return DRM_ERR(EINVAL); 308 } 309 310 return 0; 311 312error: 313 if (!dev->drw_info[id]) 314 drm_free(info, sizeof(*info), DRM_MEM_BUFS); 315 else if (rects != dev->drw_info[id]->rects) 316 drm_free(rects, update.num * 317 sizeof(drm_clip_rect_t), DRM_MEM_BUFS); 318 319 return err; 320} 321 322/** 323 * Caller must hold the drawable spinlock! 324 */ 325drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { 326 u32 *bitfield = dev->drw_bitfield; 327 unsigned int idx, shift; 328 329 id--; 330 idx = id / (8 * sizeof(*bitfield)); 331 shift = id % (8 * sizeof(*bitfield)); 332 333 if (idx < 0 || idx >= dev->drw_bitfield_length || 334 !(bitfield[idx] & (1 << shift))) { 335 DRM_DEBUG("No such drawable %d\n", id); 336 return NULL; 337 } 338 339 return dev->drw_info[id]; 340} 341EXPORT_SYMBOL(drm_get_drawable_info); 342