Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /** |
b5e89ed5 | 2 | * \file drm_drawable.c |
1da177e4 LT |
3 | * IOCTLs for drawables |
4 | * | |
5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> | |
6 | * \author Gareth Hughes <gareth@valinux.com> | |
bea5679f | 7 | * \author Michel Dänzer <michel@tungstengraphics.com> |
1da177e4 LT |
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. | |
b03ed6f2 | 15 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. |
1da177e4 LT |
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 | ||
b03ed6f2 MCA |
40 | /** |
41 | * Allocate drawable ID and memory to store information about it. | |
42 | */ | |
bea5679f | 43 | int drm_adddraw(DRM_IOCTL_ARGS) |
1da177e4 | 44 | { |
bea5679f MCA |
45 | DRM_DEVICE; |
46 | unsigned long irqflags; | |
b03ed6f2 MCA |
47 | int i, j; |
48 | u32 *bitfield = dev->drw_bitfield; | |
49 | unsigned int bitfield_length = dev->drw_bitfield_length; | |
c60ce623 | 50 | struct drm_drawable_info **info = dev->drw_info; |
b03ed6f2 | 51 | unsigned int info_length = dev->drw_info_length; |
c60ce623 | 52 | struct drm_draw draw; |
1da177e4 | 53 | |
b03ed6f2 MCA |
54 | for (i = 0, j = 0; i < bitfield_length; i++) { |
55 | if (bitfield[i] == ~0) | |
bea5679f MCA |
56 | continue; |
57 | ||
b03ed6f2 MCA |
58 | for (; j < 8 * sizeof(*bitfield); j++) |
59 | if (!(bitfield[i] & (1 << j))) | |
bea5679f MCA |
60 | goto done; |
61 | } | |
62 | done: | |
63 | ||
b03ed6f2 MCA |
64 | if (i == bitfield_length) { |
65 | bitfield_length++; | |
66 | ||
67 | bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), | |
68 | DRM_MEM_BUFS); | |
bea5679f | 69 | |
b03ed6f2 | 70 | if (!bitfield) { |
bea5679f | 71 | DRM_ERROR("Failed to allocate new drawable bitfield\n"); |
bea5679f MCA |
72 | return DRM_ERR(ENOMEM); |
73 | } | |
74 | ||
b03ed6f2 MCA |
75 | if (8 * sizeof(*bitfield) * bitfield_length > info_length) { |
76 | info_length += 8 * sizeof(*bitfield); | |
bea5679f | 77 | |
b03ed6f2 MCA |
78 | info = drm_alloc(info_length * sizeof(*info), |
79 | DRM_MEM_BUFS); | |
80 | ||
81 | if (!info) { | |
bea5679f MCA |
82 | DRM_ERROR("Failed to allocate new drawable info" |
83 | " array\n"); | |
84 | ||
b03ed6f2 MCA |
85 | drm_free(bitfield, |
86 | bitfield_length * sizeof(*bitfield), | |
87 | DRM_MEM_BUFS); | |
bea5679f MCA |
88 | return DRM_ERR(ENOMEM); |
89 | } | |
bea5679f MCA |
90 | } |
91 | ||
b03ed6f2 | 92 | bitfield[i] = 0; |
bea5679f MCA |
93 | } |
94 | ||
cdec2f82 | 95 | draw.handle = i * 8 * sizeof(*bitfield) + j + 1; |
1da177e4 | 96 | DRM_DEBUG("%d\n", draw.handle); |
bea5679f | 97 | |
b03ed6f2 MCA |
98 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
99 | ||
100 | bitfield[i] |= 1 << j; | |
cdec2f82 | 101 | info[draw.handle - 1] = NULL; |
b03ed6f2 MCA |
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 | } | |
bea5679f MCA |
120 | |
121 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | |
122 | ||
c60ce623 | 123 | DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw)); |
bea5679f | 124 | |
1da177e4 LT |
125 | return 0; |
126 | } | |
127 | ||
b03ed6f2 MCA |
128 | /** |
129 | * Free drawable ID and memory to store information about it. | |
130 | */ | |
bea5679f | 131 | int drm_rmdraw(DRM_IOCTL_ARGS) |
1da177e4 | 132 | { |
bea5679f | 133 | DRM_DEVICE; |
c60ce623 | 134 | struct drm_draw draw; |
507c0185 FCB |
135 | int id, idx; |
136 | unsigned int shift; | |
bea5679f | 137 | unsigned long irqflags; |
b03ed6f2 MCA |
138 | u32 *bitfield = dev->drw_bitfield; |
139 | unsigned int bitfield_length = dev->drw_bitfield_length; | |
c60ce623 | 140 | struct drm_drawable_info **info = dev->drw_info; |
b03ed6f2 | 141 | unsigned int info_length = dev->drw_info_length; |
bea5679f | 142 | |
c60ce623 | 143 | DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data, |
bea5679f MCA |
144 | sizeof(draw)); |
145 | ||
cdec2f82 MCA |
146 | id = draw.handle - 1; |
147 | idx = id / (8 * sizeof(*bitfield)); | |
148 | shift = id % (8 * sizeof(*bitfield)); | |
bea5679f | 149 | |
cdec2f82 | 150 | if (idx < 0 || idx >= bitfield_length || |
b03ed6f2 | 151 | !(bitfield[idx] & (1 << shift))) { |
bea5679f | 152 | DRM_DEBUG("No such drawable %d\n", draw.handle); |
bea5679f MCA |
153 | return 0; |
154 | } | |
155 | ||
b03ed6f2 MCA |
156 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
157 | ||
158 | bitfield[idx] &= ~(1 << shift); | |
159 | ||
160 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | |
bea5679f | 161 | |
cdec2f82 MCA |
162 | if (info[id]) { |
163 | drm_free(info[id]->rects, info[id]->num_rects * | |
c60ce623 | 164 | sizeof(struct drm_clip_rect), DRM_MEM_BUFS); |
cdec2f82 MCA |
165 | drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); |
166 | } | |
167 | ||
b03ed6f2 MCA |
168 | /* Can we shrink the arrays? */ |
169 | if (idx == bitfield_length - 1) { | |
170 | while (idx >= 0 && !bitfield[idx]) | |
bea5679f MCA |
171 | --idx; |
172 | ||
b03ed6f2 | 173 | bitfield_length = idx + 1; |
bea5679f | 174 | |
c4814f90 | 175 | bitfield = NULL; |
b03ed6f2 | 176 | |
c4814f90 MD |
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 | } | |
bea5679f MCA |
187 | } |
188 | } | |
189 | ||
b03ed6f2 MCA |
190 | if (bitfield != dev->drw_bitfield) { |
191 | info_length = 8 * sizeof(*bitfield) * bitfield_length; | |
192 | ||
c4814f90 MD |
193 | if (info_length) { |
194 | info = drm_alloc(info_length * sizeof(*info), | |
195 | DRM_MEM_BUFS); | |
b03ed6f2 | 196 | |
c4814f90 MD |
197 | if (!info) { |
198 | info = dev->drw_info; | |
199 | info_length = dev->drw_info_length; | |
200 | } | |
201 | } else | |
202 | info = NULL; | |
bea5679f | 203 | |
b03ed6f2 MCA |
204 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
205 | ||
c4814f90 MD |
206 | if (bitfield) |
207 | memcpy(bitfield, dev->drw_bitfield, bitfield_length * | |
208 | sizeof(*bitfield)); | |
b03ed6f2 MCA |
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) { | |
c4814f90 MD |
215 | if (info) |
216 | memcpy(info, dev->drw_info, info_length * | |
217 | sizeof(*info)); | |
b03ed6f2 MCA |
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 | } | |
bea5679f MCA |
226 | |
227 | DRM_DEBUG("%d\n", draw.handle); | |
228 | return 0; | |
229 | } | |
230 | ||
231 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { | |
232 | DRM_DEVICE; | |
c60ce623 | 233 | struct drm_update_draw update; |
b03ed6f2 MCA |
234 | unsigned int id, idx, shift; |
235 | u32 *bitfield = dev->drw_bitfield; | |
236 | unsigned long irqflags, bitfield_length = dev->drw_bitfield_length; | |
c60ce623 DA |
237 | struct drm_drawable_info *info; |
238 | struct drm_clip_rect *rects; | |
b03ed6f2 | 239 | int err; |
bea5679f | 240 | |
c60ce623 | 241 | DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data, |
bea5679f MCA |
242 | sizeof(update)); |
243 | ||
cdec2f82 | 244 | id = update.handle - 1; |
b03ed6f2 MCA |
245 | idx = id / (8 * sizeof(*bitfield)); |
246 | shift = id % (8 * sizeof(*bitfield)); | |
bea5679f | 247 | |
cdec2f82 MCA |
248 | if (idx < 0 || idx >= bitfield_length || |
249 | !(bitfield[idx] & (1 << shift))) { | |
bea5679f | 250 | DRM_ERROR("No such drawable %d\n", update.handle); |
bea5679f MCA |
251 | return DRM_ERR(EINVAL); |
252 | } | |
253 | ||
254 | info = dev->drw_info[id]; | |
255 | ||
256 | if (!info) { | |
c60ce623 | 257 | info = drm_calloc(1, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); |
bea5679f MCA |
258 | |
259 | if (!info) { | |
260 | DRM_ERROR("Failed to allocate drawable info memory\n"); | |
bea5679f MCA |
261 | return DRM_ERR(ENOMEM); |
262 | } | |
bea5679f MCA |
263 | } |
264 | ||
265 | switch (update.type) { | |
266 | case DRM_DRAWABLE_CLIPRECTS: | |
267 | if (update.num != info->num_rects) { | |
c60ce623 | 268 | rects = drm_alloc(update.num * sizeof(struct drm_clip_rect), |
b03ed6f2 MCA |
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; | |
bea5679f MCA |
277 | } |
278 | ||
b03ed6f2 | 279 | if (update.num && DRM_COPY_FROM_USER(rects, |
c60ce623 | 280 | (struct drm_clip_rect __user *) |
b03ed6f2 MCA |
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; | |
bea5679f MCA |
287 | } |
288 | ||
b03ed6f2 MCA |
289 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
290 | ||
291 | if (rects != info->rects) { | |
bea5679f | 292 | drm_free(info->rects, info->num_rects * |
c60ce623 | 293 | sizeof(struct drm_clip_rect), DRM_MEM_BUFS); |
bea5679f MCA |
294 | } |
295 | ||
b03ed6f2 MCA |
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 | ||
bea5679f MCA |
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); | |
bea5679f MCA |
307 | return DRM_ERR(EINVAL); |
308 | } | |
309 | ||
bea5679f | 310 | return 0; |
b03ed6f2 MCA |
311 | |
312 | error: | |
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 * | |
c60ce623 | 317 | sizeof(struct drm_clip_rect), DRM_MEM_BUFS); |
b03ed6f2 MCA |
318 | |
319 | return err; | |
bea5679f MCA |
320 | } |
321 | ||
322 | /** | |
323 | * Caller must hold the drawable spinlock! | |
324 | */ | |
84b1fd10 | 325 | struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id) { |
b03ed6f2 | 326 | u32 *bitfield = dev->drw_bitfield; |
cdec2f82 MCA |
327 | unsigned int idx, shift; |
328 | ||
329 | id--; | |
330 | idx = id / (8 * sizeof(*bitfield)); | |
331 | shift = id % (8 * sizeof(*bitfield)); | |
bea5679f | 332 | |
cdec2f82 | 333 | if (idx < 0 || idx >= dev->drw_bitfield_length || |
b03ed6f2 | 334 | !(bitfield[idx] & (1 << shift))) { |
bea5679f MCA |
335 | DRM_DEBUG("No such drawable %d\n", id); |
336 | return NULL; | |
337 | } | |
338 | ||
339 | return dev->drw_info[id]; | |
1da177e4 | 340 | } |
bea5679f | 341 | EXPORT_SYMBOL(drm_get_drawable_info); |