summaryrefslogtreecommitdiff
path: root/linux-core/drm_bufs.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/drm_bufs.c')
-rw-r--r--linux-core/drm_bufs.c118
1 files changed, 99 insertions, 19 deletions
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
index b7e27d172..1d5403225 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -69,6 +69,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_map_t *map;
+ drm_map_list_t *list;
if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
@@ -81,6 +82,14 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
return -EFAULT;
}
+ /* Only allow shared memory to be removable since we only keep enough
+ * book keeping information about shared memory to allow for removal
+ * when processes fork.
+ */
+ if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) {
+ DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+ return -EINVAL;
+ }
DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
map->offset, map->size, map->type );
if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) {
@@ -100,7 +109,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
return -EINVAL;
}
#endif
-#ifdef CONFIG_MTRR
+#ifdef __REALLY_HAVE_MTRR
if ( map->type == _DRM_FRAME_BUFFER ||
(map->flags & _DRM_WRITE_COMBINING) ) {
map->mtrr = mtrr_add( map->offset, map->size,
@@ -111,9 +120,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
break;
case _DRM_SHM:
- map->handle = (void *)DRM(alloc_pages)( DRM(order)( map->size )
- - PAGE_SHIFT,
- DRM_MEM_SAREA );
+ map->handle = vmalloc_32(map->size);
DRM_DEBUG( "%ld %d %p\n",
map->size, DRM(order)( map->size ), map->handle );
if ( !map->handle ) {
@@ -136,22 +143,17 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
return -EINVAL;
}
- down( &dev->struct_sem );
- if ( dev->maplist ) {
- ++dev->map_count;
- dev->maplist = DRM(realloc)( dev->maplist,
- (dev->map_count-1)
- * sizeof(*dev->maplist),
- dev->map_count
- * sizeof(*dev->maplist),
- DRM_MEM_MAPS );
- } else {
- dev->map_count = 1;
- dev->maplist = DRM(alloc)( dev->map_count*sizeof(*dev->maplist),
- DRM_MEM_MAPS );
+ list = DRM(alloc)(sizeof(*list), DRM_MEM_MAPS);
+ if(!list) {
+ DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
}
- dev->maplist[dev->map_count-1] = map;
- up( &dev->struct_sem );
+ memset(list, 0, sizeof(*list));
+ list->map = map;
+
+ down(&dev->struct_sem);
+ list_add(&list->head, &dev->maplist->head);
+ up(&dev->struct_sem);
if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) )
return -EFAULT;
@@ -164,6 +166,84 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
return 0;
}
+
+/* Remove a map private from list and deallocate resources if the mapping
+ * isn't in use.
+ */
+
+int DRM(rmmap)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ struct list_head *list;
+ drm_map_list_t *r_list;
+ drm_vma_entry_t *pt, *prev;
+ drm_map_t *map;
+ drm_map_t request;
+ int found_maps = 0;
+
+ if (copy_from_user(&request, (drm_map_t *)arg,
+ sizeof(request))) {
+ return -EFAULT;
+ }
+
+ down(&dev->struct_sem);
+ list = &dev->maplist->head;
+ list_for_each(list, &dev->maplist->head) {
+ r_list = (drm_map_list_t *) list;
+
+ if(r_list->map &&
+ r_list->map->handle == request.handle &&
+ r_list->map->flags & _DRM_REMOVABLE) break;
+ }
+
+ /* List has wrapped around to the head pointer, or its empty we didn't
+ * find anything.
+ */
+ if(list == (&dev->maplist->head)) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+ map = r_list->map;
+ list_del(list);
+ DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
+
+ for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+#if LINUX_VERSION_CODE >= 0x020300
+ if (pt->vma->vm_private_data == map) found_maps++;
+#else
+ if (pt->vma->vm_pte == map) found_maps++;
+#endif
+ }
+
+ if(!found_maps) {
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+#ifdef __REALLY_HAVE_MTRR
+ if (map->mtrr >= 0) {
+ int retcode;
+ retcode = mtrr_del(map->mtrr,
+ map->offset,
+ map->size);
+ DRM_DEBUG("mtrr_del = %d\n", retcode);
+ }
+#endif
+ DRM(ioremapfree)(map->handle, map->size);
+ break;
+ case _DRM_SHM:
+ vfree(map->handle);
+ break;
+ case _DRM_AGP:
+ break;
+ }
+ DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
+ }
+ up(&dev->struct_sem);
+ return 0;
+}
+
#if __HAVE_DMA
#if __REALLY_HAVE_AGP