5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com>
7 * \author Michel Dänzer <michel@tungstengraphics.com>
11 * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
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.
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:
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
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.
41 * Allocate drawable ID and memory to store information about it.
43 int drm_adddraw(DRM_IOCTL_ARGS
)
46 unsigned long irqflags
;
48 u32
*bitfield
= dev
->drw_bitfield
;
49 unsigned int bitfield_length
= dev
->drw_bitfield_length
;
50 struct drm_drawable_info
**info
= dev
->drw_info
;
51 unsigned int info_length
= dev
->drw_info_length
;
54 for (i
= 0, j
= 0; i
< bitfield_length
; i
++) {
55 if (bitfield
[i
] == ~0)
58 for (; j
< 8 * sizeof(*bitfield
); j
++)
59 if (!(bitfield
[i
] & (1 << j
)))
64 if (i
== bitfield_length
) {
67 bitfield
= drm_alloc(bitfield_length
* sizeof(*bitfield
),
71 DRM_ERROR("Failed to allocate new drawable bitfield\n");
72 return DRM_ERR(ENOMEM
);
75 if (8 * sizeof(*bitfield
) * bitfield_length
> info_length
) {
76 info_length
+= 8 * sizeof(*bitfield
);
78 info
= drm_alloc(info_length
* sizeof(*info
),
82 DRM_ERROR("Failed to allocate new drawable info"
86 bitfield_length
* sizeof(*bitfield
),
88 return DRM_ERR(ENOMEM
);
95 draw
.handle
= i
* 8 * sizeof(*bitfield
) + j
+ 1;
96 DRM_DEBUG("%d\n", draw
.handle
);
98 spin_lock_irqsave(&dev
->drw_lock
, irqflags
);
100 bitfield
[i
] |= 1 << j
;
101 info
[draw
.handle
- 1] = NULL
;
103 if (bitfield
!= dev
->drw_bitfield
) {
104 memcpy(bitfield
, dev
->drw_bitfield
, dev
->drw_bitfield_length
*
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
;
112 if (info
!= dev
->drw_info
) {
113 memcpy(info
, dev
->drw_info
, dev
->drw_info_length
*
115 drm_free(dev
->drw_info
, sizeof(*info
) * dev
->drw_info_length
,
117 dev
->drw_info
= info
;
118 dev
->drw_info_length
= info_length
;
121 spin_unlock_irqrestore(&dev
->drw_lock
, irqflags
);
123 DRM_COPY_TO_USER_IOCTL((struct drm_draw __user
*)data
, draw
, sizeof(draw
));
129 * Free drawable ID and memory to store information about it.
131 int drm_rmdraw(DRM_IOCTL_ARGS
)
134 struct drm_draw draw
;
137 unsigned long irqflags
;
138 u32
*bitfield
= dev
->drw_bitfield
;
139 unsigned int bitfield_length
= dev
->drw_bitfield_length
;
140 struct drm_drawable_info
**info
= dev
->drw_info
;
141 unsigned int info_length
= dev
->drw_info_length
;
143 DRM_COPY_FROM_USER_IOCTL(draw
, (struct drm_draw __user
*) data
,
146 id
= draw
.handle
- 1;
147 idx
= id
/ (8 * sizeof(*bitfield
));
148 shift
= id
% (8 * sizeof(*bitfield
));
150 if (idx
< 0 || idx
>= bitfield_length
||
151 !(bitfield
[idx
] & (1 << shift
))) {
152 DRM_DEBUG("No such drawable %d\n", draw
.handle
);
156 spin_lock_irqsave(&dev
->drw_lock
, irqflags
);
158 bitfield
[idx
] &= ~(1 << shift
);
160 spin_unlock_irqrestore(&dev
->drw_lock
, irqflags
);
163 drm_free(info
[id
]->rects
, info
[id
]->num_rects
*
164 sizeof(struct drm_clip_rect
), DRM_MEM_BUFS
);
165 drm_free(info
[id
], sizeof(**info
), DRM_MEM_BUFS
);
168 /* Can we shrink the arrays? */
169 if (idx
== bitfield_length
- 1) {
170 while (idx
>= 0 && !bitfield
[idx
])
173 bitfield_length
= idx
+ 1;
177 if (bitfield_length
) {
178 if (bitfield_length
!= dev
->drw_bitfield_length
)
179 bitfield
= drm_alloc(bitfield_length
*
184 bitfield
= dev
->drw_bitfield
;
185 bitfield_length
= dev
->drw_bitfield_length
;
190 if (bitfield
!= dev
->drw_bitfield
) {
191 info_length
= 8 * sizeof(*bitfield
) * bitfield_length
;
194 info
= drm_alloc(info_length
* sizeof(*info
),
198 info
= dev
->drw_info
;
199 info_length
= dev
->drw_info_length
;
204 spin_lock_irqsave(&dev
->drw_lock
, irqflags
);
207 memcpy(bitfield
, dev
->drw_bitfield
, bitfield_length
*
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
;
214 if (info
!= dev
->drw_info
) {
216 memcpy(info
, dev
->drw_info
, info_length
*
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
;
224 spin_unlock_irqrestore(&dev
->drw_lock
, irqflags
);
227 DRM_DEBUG("%d\n", draw
.handle
);
231 int drm_update_drawable_info(DRM_IOCTL_ARGS
) {
233 struct drm_update_draw update
;
234 unsigned int id
, idx
, shift
;
235 u32
*bitfield
= dev
->drw_bitfield
;
236 unsigned long irqflags
, bitfield_length
= dev
->drw_bitfield_length
;
237 struct drm_drawable_info
*info
;
238 struct drm_clip_rect
*rects
;
241 DRM_COPY_FROM_USER_IOCTL(update
, (struct drm_update_draw __user
*) data
,
244 id
= update
.handle
- 1;
245 idx
= id
/ (8 * sizeof(*bitfield
));
246 shift
= id
% (8 * sizeof(*bitfield
));
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
);
254 info
= dev
->drw_info
[id
];
257 info
= drm_calloc(1, sizeof(struct drm_drawable_info
), DRM_MEM_BUFS
);
260 DRM_ERROR("Failed to allocate drawable info memory\n");
261 return DRM_ERR(ENOMEM
);
265 switch (update
.type
) {
266 case DRM_DRAWABLE_CLIPRECTS
:
267 if (update
.num
!= info
->num_rects
) {
268 rects
= drm_alloc(update
.num
* sizeof(struct drm_clip_rect
),
273 if (update
.num
&& !rects
) {
274 DRM_ERROR("Failed to allocate cliprect memory\n");
275 err
= DRM_ERR(ENOMEM
);
279 if (update
.num
&& DRM_COPY_FROM_USER(rects
,
280 (struct drm_clip_rect __user
*)
281 (unsigned long)update
.data
,
284 DRM_ERROR("Failed to copy cliprects from userspace\n");
285 err
= DRM_ERR(EFAULT
);
289 spin_lock_irqsave(&dev
->drw_lock
, irqflags
);
291 if (rects
!= info
->rects
) {
292 drm_free(info
->rects
, info
->num_rects
*
293 sizeof(struct drm_clip_rect
), DRM_MEM_BUFS
);
297 info
->num_rects
= update
.num
;
298 dev
->drw_info
[id
] = info
;
300 spin_unlock_irqrestore(&dev
->drw_lock
, irqflags
);
302 DRM_DEBUG("Updated %d cliprects for drawable %d\n",
303 info
->num_rects
, id
);
306 DRM_ERROR("Invalid update type %d\n", update
.type
);
307 return DRM_ERR(EINVAL
);
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(struct drm_clip_rect
), DRM_MEM_BUFS
);
323 * Caller must hold the drawable spinlock!
325 struct drm_drawable_info
*drm_get_drawable_info(struct drm_device
*dev
, drm_drawable_t id
) {
326 u32
*bitfield
= dev
->drw_bitfield
;
327 unsigned int idx
, shift
;
330 idx
= id
/ (8 * sizeof(*bitfield
));
331 shift
= id
% (8 * sizeof(*bitfield
));
333 if (idx
< 0 || idx
>= dev
->drw_bitfield_length
||
334 !(bitfield
[idx
] & (1 << shift
))) {
335 DRM_DEBUG("No such drawable %d\n", id
);
339 return dev
->drw_info
[id
];
341 EXPORT_SYMBOL(drm_get_drawable_info
);