| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /** | |||
| 2 | * \file drm_bufs.c | |||
| 3 | * Generic buffer template | |||
| 4 | * | |||
| 5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> | |||
| 6 | * \author Gareth Hughes <gareth@valinux.com> | |||
| 7 | */ | |||
| 8 | ||||
| 9 | /* | |||
| 10 | * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com | |||
| 11 | * | |||
| 12 | * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. | |||
| 13 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | |||
| 14 | * All Rights Reserved. | |||
| 15 | * | |||
| 16 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
| 17 | * copy of this software and associated documentation files (the "Software"), | |||
| 18 | * to deal in the Software without restriction, including without limitation | |||
| 19 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
| 20 | * and/or sell copies of the Software, and to permit persons to whom the | |||
| 21 | * Software is furnished to do so, subject to the following conditions: | |||
| 22 | * | |||
| 23 | * The above copyright notice and this permission notice (including the next | |||
| 24 | * paragraph) shall be included in all copies or substantial portions of the | |||
| 25 | * Software. | |||
| 26 | * | |||
| 27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| 28 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| 29 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| 30 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
| 31 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
| 32 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
| 33 | * OTHER DEALINGS IN THE SOFTWARE. | |||
| 34 | */ | |||
| 35 | ||||
| 36 | #include <linux/vmalloc.h> | |||
| 37 | #include "drmP.h" | |||
| 38 | ||||
| 0 | 0 | - | 39 | unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource) |
| 40 | { | |||
| 0 | - | 41 | return pci_resource_start(dev->pdev, resource); | |
| 42 | } | |||
| 43 | EXPORT_SYMBOL(drm_get_resource_start); | |||
| 44 | ||||
| 0 | 0 | - | 45 | unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) |
| 46 | { | |||
| 47 | return pci_resource_len(dev->pdev, resource); | |||
| 0 | 0 | - | 47 | ternary-?: ( ( ( ( dev -> pdev ) ) -> resource.. |
| 0 | - | 47 | return ( ( ( ( ( dev -> pdev ) ) -> resource [.. | |
| 48 | } | |||
| 49 | ||||
| 50 | EXPORT_SYMBOL(drm_get_resource_len); | |||
| 51 | ||||
| 0 | 0 | - | 52 | static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, |
| 53 | drm_local_map_t *map) | |||
| 54 | { | |||
| 55 | struct list_head *list; | |||
| 56 | ||||
| 0 | 0 | - | 57 | list_for_each(list, &dev->maplist->head) { |
| 58 | drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); | |||
| 59 | if (entry->map && map->type == entry->map->type && | |||
| 0 | 0 | - | 60 | entry->map->offset == map->offset) { |
| 0 | - | 60 | T && T && T | |
| 0 | - | 60 | T && T && F | |
| 0 | - | 60 | T && F && _ | |
| 0 | - | 60 | F && _ && _ | |
| 0 | - | 61 | return entry; | |
| 62 | } | |||
| 63 | } | |||
| 64 | ||||
| 0 | - | 65 | return NULL; | |
| 66 | } | |||
| 67 | ||||
| 68 | /* | |||
| 69 | * Used to allocate 32-bit handles for mappings. | |||
| 70 | */ | |||
| 71 | #define START_RANGE 0x10000000 | |||
| 72 | #define END_RANGE 0x40000000 | |||
| 73 | ||||
| 74 | #ifdef _LP64 | |||
| 0 | 0 | - | 75 | static __inline__ unsigned int HandleID(unsigned long lhandle, |
| 76 | drm_device_t *dev) | |||
| 77 | { | |||
| 78 | static unsigned int map32_handle = START_RANGE; | |||
| 79 | unsigned int hash; | |||
| 80 | ||||
| 0 | 0 | - | 81 | if (lhandle & 0xffffffff00000000) { |
| 82 | hash = map32_handle; | |||
| 83 | map32_handle += PAGE_SIZE; | |||
| 0 | 0 | - | 84 | if (map32_handle > END_RANGE) |
| 85 | map32_handle = START_RANGE; | |||
| 86 | } else | |||
| 87 | hash = lhandle; | |||
| 88 | ||||
| 0 | 0 | - | 89 | while (1) { |
| 90 | drm_map_list_t *_entry; | |||
| 0 | 0 | - | 91 | list_for_each_entry(_entry, &dev->maplist->head, head) { |
| 0 | 0 | - | 92 | if (_entry->user_token == hash) |
| 0 | - | 93 | break; | |
| 94 | } | |||
| 0 | 0 | - | 95 | if (&_entry->head == &dev->maplist->head) |
| 0 | - | 96 | return hash; | |
| 97 | ||||
| 98 | hash += PAGE_SIZE; | |||
| 99 | map32_handle += PAGE_SIZE; | |||
| 100 | } | |||
| 101 | } | |||
| 102 | #else | |||
| 103 | # define HandleID(x,dev) (unsigned int)(x) | |||
| 104 | #endif | |||
| 105 | ||||
| 106 | /** | |||
| 107 | * Ioctl to specify a range of memory that is available for mapping by a non-root process. | |||
| 108 | * | |||
| 109 | * \param inode device inode. | |||
| 110 | * \param filp file pointer. | |||
| 111 | * \param cmd command. | |||
| 112 | * \param arg pointer to a drm_map structure. | |||
| 113 | * \return zero on success or a negative value on error. | |||
| 114 | * | |||
| 115 | * Adjusts the memory offset to its absolute value according to the mapping | |||
| 116 | * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where | |||
| 117 | * applicable and if supported by the kernel. | |||
| 118 | */ | |||
| 0 | 0 | - | 119 | static int drm_addmap_core(drm_device_t * dev, unsigned int offset, |
| 120 | unsigned int size, drm_map_type_t type, | |||
| 121 | drm_map_flags_t flags, drm_map_list_t ** maplist) | |||
| 122 | { | |||
| 123 | drm_map_t *map; | |||
| 124 | drm_map_list_t *list; | |||
| 125 | drm_dma_handle_t *dmah; | |||
| 126 | ||||
| 127 | map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | 0 | - | 128 | if (!map) |
| 0 | - | 129 | return -ENOMEM; | |
| 130 | ||||
| 131 | map->offset = offset; | |||
| 132 | map->size = size; | |||
| 133 | map->flags = flags; | |||
| 134 | map->type = type; | |||
| 135 | ||||
| 136 | /* Only allow shared memory to be removable since we only keep enough | |||
| 137 | * book keeping information about shared memory to allow for removal | |||
| 138 | * when processes fork. | |||
| 139 | */ | |||
| 0 | 0 | - | 140 | if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { |
| 0 | - | 140 | (T) && T | |
| 0 | - | 140 | (T) && F | |
| 0 | - | 140 | (F) && _ | |
| 141 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 142 | return -EINVAL; | |
| 143 | } | |||
| 144 | DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", | |||
| 0 | 0 | - | 144 | if (drm_debug) |
| 0 | 0 | - | 144 | do-while (0) |
| 145 | map->offset, map->size, map->type); | |||
| 0 | 0 | - | 146 | if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) { |
| 0 | - | 146 | (T) || (_) | |
| 0 | - | 146 | (F) || (T) | |
| 0 | - | 146 | (F) || (F) | |
| 147 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 148 | return -EINVAL; | |
| 149 | } | |||
| 150 | map->mtrr = -1; | |||
| 151 | map->handle = NULL; | |||
| 152 | ||||
| 153 | switch (map->type) { | |||
| 0 | - | 154 | case _DRM_REGISTERS: | |
| 0 | - | 155 | case _DRM_FRAME_BUFFER: | |
| 156 | #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) | |||
| 157 | if (map->offset + (map->size-1) < map->offset || | |||
| 158 | map->offset < virt_to_phys(high_memory)) { | |||
| 159 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 160 | return -EINVAL; | |||
| 161 | } | |||
| 162 | #endif | |||
| 163 | #ifdef __alpha__ | |||
| 164 | map->offset += dev->hose->mem_space->start; | |||
| 165 | #endif | |||
| 166 | /* Some drivers preinitialize some maps, without the X Server | |||
| 167 | * needing to be aware of it. Therefore, we just return success | |||
| 168 | * when the server tries to create a duplicate map. | |||
| 169 | */ | |||
| 170 | list = drm_find_matching_map(dev, map); | |||
| 0 | 0 | - | 171 | if (list != NULL) { |
| 0 | 0 | - | 172 | if (list->map->size != map->size) { |
| 173 | DRM_DEBUG("Matching maps of type %d with " | |||
| 0 | 0 | - | 173 | if (drm_debug) |
| 0 | 0 | - | 173 | do-while (0) |
| 174 | "mismatched sizes, (%ld vs %ld)\n", | |||
| 175 | map->type, map->size, | |||
| 176 | list->map->size); | |||
| 177 | list->map->size = map->size; | |||
| 178 | } | |||
| 179 | ||||
| 180 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 181 | *maplist = list; | |||
| 0 | - | 182 | return 0; | |
| 183 | } | |||
| 184 | ||||
| 0 | 0 | - | 185 | if (drm_core_has_MTRR(dev)) { |
| 186 | if (map->type == _DRM_FRAME_BUFFER || | |||
| 0 | 0 | - | 187 | (map->flags & _DRM_WRITE_COMBINING)) { |
| 0 | - | 187 | T || (_) | |
| 0 | - | 187 | F || (T) | |
| 0 | - | 187 | F || (F) | |
| 188 | map->mtrr = mtrr_add(map->offset, map->size, | |||
| 189 | MTRR_TYPE_WRCOMB, 1); | |||
| 190 | } | |||
| 191 | } | |||
| 0 | 0 | - | 192 | if (map->type == _DRM_REGISTERS) |
| 193 | map->handle = drm_ioremap(map->offset, map->size, dev); | |||
| 0 | - | 194 | break; | |
| 195 | ||||
| 0 | - | 196 | case _DRM_SHM: | |
| 197 | map->handle = vmalloc_32(map->size); | |||
| 198 | DRM_DEBUG("%lu %d %p\n", | |||
| 0 | 0 | - | 198 | if (drm_debug) |
| 0 | 0 | - | 198 | do-while (0) |
| 199 | map->size, drm_order(map->size), map->handle); | |||
| 0 | 0 | - | 200 | if (!map->handle) { |
| 201 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 202 | return -ENOMEM; | |
| 203 | } | |||
| 204 | map->offset = (unsigned long)map->handle; | |||
| 0 | 0 | - | 205 | if (map->flags & _DRM_CONTAINS_LOCK) { |
| 206 | /* Prevent a 2nd X Server from creating a 2nd lock */ | |||
| 0 | 0 | - | 207 | if (dev->lock.hw_lock != NULL) { |
| 208 | vfree(map->handle); | |||
| 209 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 210 | return -EBUSY; | |
| 211 | } | |||
| 212 | dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ | |||
| 213 | } | |||
| 0 | - | 214 | break; | |
| 0 | - | 215 | case _DRM_AGP: | |
| 0 | 0 | - | 216 | if (drm_core_has_AGP(dev)) { |
| 217 | #ifdef __alpha__ | |||
| 218 | map->offset += dev->hose->mem_space->start; | |||
| 219 | #endif | |||
| 220 | map->offset += dev->agp->base; | |||
| 221 | map->mtrr = dev->agp->agp_mtrr; /* for getmap */ | |||
| 222 | } | |||
| 0 | - | 223 | break; | |
| 0 | - | 224 | case _DRM_SCATTER_GATHER: | |
| 0 | 0 | - | 225 | if (!dev->sg) { |
| 226 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 227 | return -EINVAL; | |
| 228 | } | |||
| 229 | map->offset += (unsigned long)dev->sg->virtual; | |||
| 0 | - | 230 | break; | |
| 0 | - | 231 | case _DRM_CONSISTENT: | |
| 232 | /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, | |||
| 233 | * As we're limiting the address to 2^32-1 (or less), | |||
| 234 | * casting it down to 32 bits is no problem, but we | |||
| 235 | * need to point to a 64bit variable first. */ | |||
| 236 | dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); | |||
| 0 | 0 | - | 237 | if (!dmah) { |
| 238 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 239 | return -ENOMEM; | |
| 240 | } | |||
| 241 | map->handle = dmah->vaddr; | |||
| 242 | map->offset = (unsigned long)dmah->busaddr; | |||
| 243 | kfree(dmah); | |||
| 0 | - | 244 | break; | |
| 0 | - | 245 | default: | |
| 246 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 247 | return -EINVAL; | |
| 248 | } | |||
| 249 | ||||
| 250 | list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); | |||
| 0 | 0 | - | 251 | if (!list) { |
| 252 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 0 | - | 253 | return -EINVAL; | |
| 254 | } | |||
| 255 | memset(list, 0, sizeof(*list)); | |||
| 256 | list->map = map; | |||
| 257 | ||||
| 258 | mutex_lock(&dev->struct_mutex); | |||
| 259 | list_add(&list->head, &dev->maplist->head); | |||
| 260 | /* Assign a 32-bit handle */ | |||
| 261 | /* We do it here so that dev->struct_mutex protects the increment */ | |||
| 262 | list->user_token = HandleID(map->type == _DRM_SHM | |||
| 263 | ? (unsigned long)map->handle | |||
| 0 | 0 | - | 263 | ternary-?: map -> type == _DRM_SHM |
| 264 | : map->offset, dev); | |||
| 265 | mutex_unlock(&dev->struct_mutex); | |||
| 266 | ||||
| 267 | *maplist = list; | |||
| 0 | - | 268 | return 0; | |
| 269 | } | |||
| 270 | ||||
| 0 | 0 | - | 271 | int drm_addmap(drm_device_t * dev, unsigned int offset, |
| 272 | unsigned int size, drm_map_type_t type, | |||
| 273 | drm_map_flags_t flags, drm_local_map_t ** map_ptr) | |||
| 274 | { | |||
| 275 | drm_map_list_t *list; | |||
| 276 | int rc; | |||
| 277 | ||||
| 278 | rc = drm_addmap_core(dev, offset, size, type, flags, &list); | |||
| 0 | 0 | - | 279 | if (!rc) |
| 280 | *map_ptr = list->map; | |||
| 0 | - | 281 | return rc; | |
| 282 | } | |||
| 283 | ||||
| 284 | EXPORT_SYMBOL(drm_addmap); | |||
| 285 | ||||
| 0 | 0 | - | 286 | int drm_addmap_ioctl(struct inode *inode, struct file *filp, |
| 287 | unsigned int cmd, unsigned long arg) | |||
| 288 | { | |||
| 289 | drm_file_t *priv = filp->private_data; | |||
| 290 | drm_device_t *dev = priv->head->dev; | |||
| 291 | drm_map_t map; | |||
| 292 | drm_map_list_t *maplist; | |||
| 293 | drm_map_t __user *argp = (void __user *)arg; | |||
| 294 | int err; | |||
| 295 | ||||
| 0 | 0 | - | 296 | if (!(filp->f_mode & 3)) |
| 0 | - | 297 | return -EACCES; /* Require read/write */ | |
| 298 | ||||
| 0 | 0 | - | 299 | if (copy_from_user(&map, argp, sizeof(map))) { |
| 0 | - | 300 | return -EFAULT; | |
| 301 | } | |||
| 302 | ||||
| 0 | 0 | - | 303 | if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP)) |
| 0 | - | 303 | !(F || F) | |
| 0 | - | 303 | !(T || _) | |
| 0 | - | 303 | !(F || T) | |
| 0 | - | 304 | return -EPERM; | |
| 305 | ||||
| 306 | err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags, | |||
| 307 | &maplist); | |||
| 308 | ||||
| 0 | 0 | - | 309 | if (err) |
| 0 | - | 310 | return err; | |
| 311 | ||||
| 0 | 0 | - | 312 | if (copy_to_user(argp, maplist->map, sizeof(drm_map_t))) |
| 0 | - | 313 | return -EFAULT; | |
| 314 | ||||
| 315 | /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ | |||
| 0 | 0 | - | 316 | if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle)) |
| 0 | - | 317 | return -EFAULT; | |
| 0 | - | 318 | return 0; | |
| 319 | } | |||
| 320 | ||||
| 321 | /** | |||
| 322 | * Remove a map private from list and deallocate resources if the mapping | |||
| 323 | * isn't in use. | |||
| 324 | * | |||
| 325 | * \param inode device inode. | |||
| 326 | * \param filp file pointer. | |||
| 327 | * \param cmd command. | |||
| 328 | * \param arg pointer to a drm_map_t structure. | |||
| 329 | * \return zero on success or a negative value on error. | |||
| 330 | * | |||
| 331 | * Searches the map on drm_device::maplist, removes it from the list, see if | |||
| 332 | * its being used, and free any associate resource (such as MTRR's) if it's not | |||
| 333 | * being on use. | |||
| 334 | * | |||
| 335 | * \sa drm_addmap | |||
| 336 | */ | |||
| 0 | 0 | - | 337 | int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) |
| 338 | { | |||
| 339 | struct list_head *list; | |||
| 340 | drm_map_list_t *r_list = NULL; | |||
| 341 | drm_dma_handle_t dmah; | |||
| 342 | ||||
| 343 | /* Find the list entry for the map and remove it */ | |||
| 0 | 0 | - | 344 | list_for_each(list, &dev->maplist->head) { |
| 345 | r_list = list_entry(list, drm_map_list_t, head); | |||
| 346 | ||||
| 0 | 0 | - | 347 | if (r_list->map == map) { |
| 348 | list_del(list); | |||
| 349 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | |||
| 0 | - | 350 | break; | |
| 351 | } | |||
| 352 | } | |||
| 353 | ||||
| 354 | /* List has wrapped around to the head pointer, or it's empty and we | |||
| 355 | * didn't find anything. | |||
| 356 | */ | |||
| 0 | 0 | - | 357 | if (list == (&dev->maplist->head)) { |
| 0 | - | 358 | return -EINVAL; | |
| 359 | } | |||
| 360 | ||||
| 361 | switch (map->type) { | |||
| 0 | - | 362 | case _DRM_REGISTERS: | |
| 363 | drm_ioremapfree(map->handle, map->size, dev); | |||
| 364 | /* FALLTHROUGH */ | |||
| 0 | - | 365 | case _DRM_FRAME_BUFFER: | |
| 0 | 0 | - | 366 | if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { |
| 0 | - | 366 | T && T | |
| 0 | - | 366 | T && F | |
| 0 | - | 366 | F && _ | |
| 367 | int retcode; | |||
| 368 | retcode = mtrr_del(map->mtrr, map->offset, map->size); | |||
| 369 | DRM_DEBUG("mtrr_del=%d\n", retcode); | |||
| 0 | 0 | - | 369 | if (drm_debug) |
| 0 | 0 | - | 369 | do-while (0) |
| 370 | } | |||
| 0 | - | 371 | break; | |
| 0 | - | 372 | case _DRM_SHM: | |
| 373 | vfree(map->handle); | |||
| 0 | - | 374 | break; | |
| 0 | - | 375 | case _DRM_AGP: | |
| 0 | - | 376 | case _DRM_SCATTER_GATHER: | |
| 0 | - | 377 | break; | |
| 0 | - | 378 | case _DRM_CONSISTENT: | |
| 379 | dmah.vaddr = map->handle; | |||
| 380 | dmah.busaddr = map->offset; | |||
| 381 | dmah.size = map->size; | |||
| 382 | __drm_pci_free(dev, &dmah); | |||
| 0 | - | 383 | break; | |
| 384 | } | |||
| 385 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | |||
| 386 | ||||
| 0 | - | 387 | return 0; | |
| 388 | } | |||
| 389 | EXPORT_SYMBOL(drm_rmmap_locked); | |||
| 390 | ||||
| 0 | 0 | - | 391 | int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) |
| 392 | { | |||
| 393 | int ret; | |||
| 394 | ||||
| 395 | mutex_lock(&dev->struct_mutex); | |||
| 396 | ret = drm_rmmap_locked(dev, map); | |||
| 397 | mutex_unlock(&dev->struct_mutex); | |||
| 398 | ||||
| 0 | - | 399 | return ret; | |
| 400 | } | |||
| 401 | EXPORT_SYMBOL(drm_rmmap); | |||
| 402 | ||||
| 403 | /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on | |||
| 404 | * the last close of the device, and this is necessary for cleanup when things | |||
| 405 | * exit uncleanly. Therefore, having userland manually remove mappings seems | |||
| 406 | * like a pointless exercise since they're going away anyway. | |||
| 407 | * | |||
| 408 | * One use case might be after addmap is allowed for normal users for SHM and | |||
| 409 | * gets used by drivers that the server doesn't need to care about. This seems | |||
| 410 | * unlikely. | |||
| 411 | */ | |||
| 0 | 0 | - | 412 | int drm_rmmap_ioctl(struct inode *inode, struct file *filp, |
| 413 | unsigned int cmd, unsigned long arg) | |||
| 414 | { | |||
| 415 | drm_file_t *priv = filp->private_data; | |||
| 416 | drm_device_t *dev = priv->head->dev; | |||
| 417 | drm_map_t request; | |||
| 418 | drm_local_map_t *map = NULL; | |||
| 419 | struct list_head *list; | |||
| 420 | int ret; | |||
| 421 | ||||
| 0 | 0 | - | 422 | if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) { |
| 0 | - | 423 | return -EFAULT; | |
| 424 | } | |||
| 425 | ||||
| 426 | mutex_lock(&dev->struct_mutex); | |||
| 0 | 0 | - | 427 | list_for_each(list, &dev->maplist->head) { |
| 428 | drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); | |||
| 429 | ||||
| 430 | if (r_list->map && | |||
| 431 | r_list->user_token == (unsigned long)request.handle && | |||
| 0 | 0 | - | 432 | r_list->map->flags & _DRM_REMOVABLE) { |
| 0 | - | 432 | T && T && T | |
| 0 | - | 432 | T && T && F | |
| 0 | - | 432 | T && F && _ | |
| 0 | - | 432 | F && _ && _ | |
| 433 | map = r_list->map; | |||
| 0 | - | 434 | break; | |
| 435 | } | |||
| 436 | } | |||
| 437 | ||||
| 438 | /* List has wrapped around to the head pointer, or its empty we didn't | |||
| 439 | * find anything. | |||
| 440 | */ | |||
| 0 | 0 | - | 441 | if (list == (&dev->maplist->head)) { |
| 442 | mutex_unlock(&dev->struct_mutex); | |||
| 0 | - | 443 | return -EINVAL; | |
| 444 | } | |||
| 445 | ||||
| 0 | 0 | - | 446 | if (!map) |
| 0 | - | 447 | return -EINVAL; | |
| 448 | ||||
| 449 | /* Register and framebuffer maps are permanent */ | |||
| 0 | 0 | - | 450 | if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { |
| 0 | - | 450 | (T) || (_) | |
| 0 | - | 450 | (F) || (T) | |
| 0 | - | 450 | (F) || (F) | |
| 451 | mutex_unlock(&dev->struct_mutex); | |||
| 0 | - | 452 | return 0; | |
| 453 | } | |||
| 454 | ||||
| 455 | ret = drm_rmmap_locked(dev, map); | |||
| 456 | ||||
| 457 | mutex_unlock(&dev->struct_mutex); | |||
| 458 | ||||
| 0 | - | 459 | return ret; | |
| 460 | } | |||
| 461 | ||||
| 462 | /** | |||
| 463 | * Cleanup after an error on one of the addbufs() functions. | |||
| 464 | * | |||
| 465 | * \param dev DRM device. | |||
| 466 | * \param entry buffer entry where the error occurred. | |||
| 467 | * | |||
| 468 | * Frees any pages and buffers associated with the given entry. | |||
| 469 | */ | |||
| 0 | 0 | - | 470 | static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry) |
| 471 | { | |||
| 472 | int i; | |||
| 473 | ||||
| 0 | 0 | - | 474 | if (entry->seg_count)&nb |