Home | History | Annotate | Line # | Download | only in bsd-core
      1 /*-
      2  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
      3  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Rickard E. (Rik) Faith <faith (at) valinux.com>
     27  *    Gareth Hughes <gareth (at) valinux.com>
     28  *
     29  */
     30 
     31 /** @file drm_drawable.c
     32  * This file implements ioctls to store information along with DRM drawables,
     33  * such as the current set of cliprects for vblank-synced buffer swaps.
     34  */
     35 
     36 #include "drmP.h"
     37 
     38 struct bsd_drm_drawable_info {
     39 	struct drm_drawable_info info;
     40 	int handle;
     41 	RB_ENTRY(bsd_drm_drawable_info) tree;
     42 };
     43 
     44 static int
     45 drm_drawable_compare(struct bsd_drm_drawable_info *a,
     46     struct bsd_drm_drawable_info *b)
     47 {
     48 	if (a->handle > b->handle)
     49 		return 1;
     50 	if (a->handle < b->handle)
     51 		return -1;
     52 	return 0;
     53 }
     54 
     55 RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree,
     56     drm_drawable_compare);
     57 
     58 struct drm_drawable_info *
     59 drm_get_drawable_info(struct drm_device *dev, int handle)
     60 {
     61 	struct bsd_drm_drawable_info find, *result;
     62 
     63 	find.handle = handle;
     64 	result = RB_FIND(drawable_tree, &dev->drw_head, &find);
     65 
     66 	return &result->info;
     67 }
     68 
     69 int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
     70 {
     71 	struct drm_draw *draw = data;
     72 	struct bsd_drm_drawable_info *info;
     73 
     74 	info = malloc(sizeof(struct bsd_drm_drawable_info), DRM_MEM_DRAWABLE,
     75 	    M_NOWAIT | M_ZERO);
     76 	if (info == NULL)
     77 		return ENOMEM;
     78 
     79 #if defined(__FreeBSD__)
     80 	info->handle = alloc_unr(dev->drw_unrhdr);
     81 #endif
     82 	DRM_SPINLOCK(&dev->drw_lock);
     83 #if defined(__NetBSD__)
     84 	info->handle = ++dev->drw_no;
     85 #endif
     86 	RB_INSERT(drawable_tree, &dev->drw_head, info);
     87 	draw->handle = info->handle;
     88 	DRM_SPINUNLOCK(&dev->drw_lock);
     89 
     90 	DRM_DEBUG("%d\n", draw->handle);
     91 
     92 	return 0;
     93 }
     94 
     95 int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
     96 {
     97 	struct drm_draw *draw = (struct drm_draw *)data;
     98 	struct drm_drawable_info *info;
     99 
    100 	DRM_SPINLOCK(&dev->drw_lock);
    101 	info = drm_get_drawable_info(dev, draw->handle);
    102 	if (info != NULL) {
    103 		RB_REMOVE(drawable_tree, &dev->drw_head,
    104 		    (struct bsd_drm_drawable_info *)info);
    105 		DRM_SPINUNLOCK(&dev->drw_lock);
    106 #if defined(__FreeBSD__)
    107 		free_unr(dev->drw_unrhdr, draw->handle);
    108 #endif
    109 		if (info->rects)
    110 			free(info->rects, DRM_MEM_DRAWABLE);
    111 		free(info, DRM_MEM_DRAWABLE);
    112 		return 0;
    113 	} else {
    114 		DRM_SPINUNLOCK(&dev->drw_lock);
    115 		return EINVAL;
    116 	}
    117 }
    118 
    119 int drm_update_draw(struct drm_device *dev, void *data,
    120 		    struct drm_file *file_priv)
    121 {
    122 	struct drm_drawable_info *info;
    123 	struct drm_update_draw *update = (struct drm_update_draw *)data;
    124 	int ret;
    125 
    126 	info = drm_get_drawable_info(dev, update->handle);
    127 	if (info == NULL)
    128 		return EINVAL;
    129 
    130 	switch (update->type) {
    131 	case DRM_DRAWABLE_CLIPRECTS:
    132 		DRM_SPINLOCK(&dev->drw_lock);
    133 		if (update->num != info->num_rects) {
    134 			if (info->rects)
    135 				free(info->rects, DRM_MEM_DRAWABLE);
    136 			info->rects = NULL;
    137 			info->num_rects = 0;
    138 		}
    139 		if (update->num == 0) {
    140 			DRM_SPINUNLOCK(&dev->drw_lock);
    141 			return 0;
    142 		}
    143 		if (info->rects == NULL) {
    144 			info->rects = malloc(sizeof(*info->rects) *
    145 			    update->num, DRM_MEM_DRAWABLE, M_NOWAIT);
    146 			if (info->rects == NULL) {
    147 				DRM_SPINUNLOCK(&dev->drw_lock);
    148 				return ENOMEM;
    149 			}
    150 			info->num_rects = update->num;
    151 		}
    152 		/* For some reason the pointer arg is unsigned long long. */
    153 		ret = copyin((void *)(intptr_t)update->data, info->rects,
    154 		    sizeof(*info->rects) * info->num_rects);
    155 		DRM_SPINUNLOCK(&dev->drw_lock);
    156 		return ret;
    157 	default:
    158 		return EINVAL;
    159 	}
    160 }
    161 
    162 void drm_drawable_free_all(struct drm_device *dev)
    163 {
    164 	struct bsd_drm_drawable_info *info, *next;
    165 
    166 	DRM_SPINLOCK(&dev->drw_lock);
    167 	for (info = RB_MIN(drawable_tree, &dev->drw_head);
    168 	    info != NULL ; info = next) {
    169 		next = RB_NEXT(drawable_tree, &dev->drw_head, info);
    170 		RB_REMOVE(drawable_tree, &dev->drw_head,
    171 		    (struct bsd_drm_drawable_info *)info);
    172 		DRM_SPINUNLOCK(&dev->drw_lock);
    173 #if defined(__FreeBSD__)
    174 		free_unr(dev->drw_unrhdr, info->handle);
    175 #endif
    176 		if (info->info.rects)
    177 			free(info->info.rects, DRM_MEM_DRAWABLE);
    178 		free(info, DRM_MEM_DRAWABLE);
    179 		DRM_SPINLOCK(&dev->drw_lock);
    180 	}
    181 	DRM_SPINUNLOCK(&dev->drw_lock);
    182 }
    183