diff options
Diffstat (limited to 'drivers/char/drm/drm_drawable.c')
-rw-r--r-- | drivers/char/drm/drm_drawable.c | 294 |
1 files changed, 284 insertions, 10 deletions
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c index 7857453c4f48..de37d5f74563 100644 --- a/drivers/char/drm/drm_drawable.c +++ b/drivers/char/drm/drm_drawable.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * | 4 | * |
5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> | 5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> |
6 | * \author Gareth Hughes <gareth@valinux.com> | 6 | * \author Gareth Hughes <gareth@valinux.com> |
7 | * \author Michel Dänzer <michel@tungstengraphics.com> | ||
7 | */ | 8 | */ |
8 | 9 | ||
9 | /* | 10 | /* |
@@ -11,6 +12,7 @@ | |||
11 | * | 12 | * |
12 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | 13 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. |
13 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | 14 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. |
15 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. | ||
14 | * All Rights Reserved. | 16 | * All Rights Reserved. |
15 | * | 17 | * |
16 | * Permission is hereby granted, free of charge, to any person obtaining a | 18 | * Permission is hereby granted, free of charge, to any person obtaining a |
@@ -35,22 +37,294 @@ | |||
35 | 37 | ||
36 | #include "drmP.h" | 38 | #include "drmP.h" |
37 | 39 | ||
38 | /** No-op. */ | 40 | /** |
39 | int drm_adddraw(struct inode *inode, struct file *filp, | 41 | * Allocate drawable ID and memory to store information about it. |
40 | unsigned int cmd, unsigned long arg) | 42 | */ |
43 | int drm_adddraw(DRM_IOCTL_ARGS) | ||
41 | { | 44 | { |
45 | DRM_DEVICE; | ||
46 | unsigned long irqflags; | ||
47 | int i, j; | ||
48 | u32 *bitfield = dev->drw_bitfield; | ||
49 | unsigned int bitfield_length = dev->drw_bitfield_length; | ||
50 | drm_drawable_info_t **info = dev->drw_info; | ||
51 | unsigned int info_length = dev->drw_info_length; | ||
42 | drm_draw_t draw; | 52 | drm_draw_t draw; |
43 | 53 | ||
44 | draw.handle = 0; /* NOOP */ | 54 | for (i = 0, j = 0; i < bitfield_length; i++) { |
55 | if (bitfield[i] == ~0) | ||
56 | continue; | ||
57 | |||
58 | for (; j < 8 * sizeof(*bitfield); j++) | ||
59 | if (!(bitfield[i] & (1 << j))) | ||
60 | goto done; | ||
61 | } | ||
62 | done: | ||
63 | |||
64 | if (i == bitfield_length) { | ||
65 | bitfield_length++; | ||
66 | |||
67 | bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), | ||
68 | DRM_MEM_BUFS); | ||
69 | |||
70 | if (!bitfield) { | ||
71 | DRM_ERROR("Failed to allocate new drawable bitfield\n"); | ||
72 | return DRM_ERR(ENOMEM); | ||
73 | } | ||
74 | |||
75 | if (8 * sizeof(*bitfield) * bitfield_length > info_length) { | ||
76 | info_length += 8 * sizeof(*bitfield); | ||
77 | |||
78 | info = drm_alloc(info_length * sizeof(*info), | ||
79 | DRM_MEM_BUFS); | ||
80 | |||
81 | if (!info) { | ||
82 | DRM_ERROR("Failed to allocate new drawable info" | ||
83 | " array\n"); | ||
84 | |||
85 | drm_free(bitfield, | ||
86 | bitfield_length * sizeof(*bitfield), | ||
87 | DRM_MEM_BUFS); | ||
88 | return DRM_ERR(ENOMEM); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | bitfield[i] = 0; | ||
93 | } | ||
94 | |||
95 | draw.handle = i * 8 * sizeof(*bitfield) + j + 1; | ||
45 | DRM_DEBUG("%d\n", draw.handle); | 96 | DRM_DEBUG("%d\n", draw.handle); |
46 | if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw))) | 97 | |
47 | return -EFAULT; | 98 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
99 | |||
100 | bitfield[i] |= 1 << j; | ||
101 | info[draw.handle - 1] = NULL; | ||
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 | } | ||
120 | |||
121 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
122 | |||
123 | DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); | ||
124 | |||
48 | return 0; | 125 | return 0; |
49 | } | 126 | } |
50 | 127 | ||
51 | /** No-op. */ | 128 | /** |
52 | int drm_rmdraw(struct inode *inode, struct file *filp, | 129 | * Free drawable ID and memory to store information about it. |
53 | unsigned int cmd, unsigned long arg) | 130 | */ |
131 | int drm_rmdraw(DRM_IOCTL_ARGS) | ||
54 | { | 132 | { |
55 | return 0; /* NOOP */ | 133 | DRM_DEVICE; |
134 | drm_draw_t draw; | ||
135 | int id, idx; | ||
136 | unsigned int shift; | ||
137 | unsigned long irqflags; | ||
138 | u32 *bitfield = dev->drw_bitfield; | ||
139 | unsigned int bitfield_length = dev->drw_bitfield_length; | ||
140 | drm_drawable_info_t **info = dev->drw_info; | ||
141 | unsigned int info_length = dev->drw_info_length; | ||
142 | |||
143 | DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, | ||
144 | sizeof(draw)); | ||
145 | |||
146 | id = draw.handle - 1; | ||
147 | idx = id / (8 * sizeof(*bitfield)); | ||
148 | shift = id % (8 * sizeof(*bitfield)); | ||
149 | |||
150 | if (idx < 0 || idx >= bitfield_length || | ||
151 | !(bitfield[idx] & (1 << shift))) { | ||
152 | DRM_DEBUG("No such drawable %d\n", draw.handle); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
157 | |||
158 | bitfield[idx] &= ~(1 << shift); | ||
159 | |||
160 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
161 | |||
162 | if (info[id]) { | ||
163 | drm_free(info[id]->rects, info[id]->num_rects * | ||
164 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | ||
165 | drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); | ||
166 | } | ||
167 | |||
168 | /* Can we shrink the arrays? */ | ||
169 | if (idx == bitfield_length - 1) { | ||
170 | while (idx >= 0 && !bitfield[idx]) | ||
171 | --idx; | ||
172 | |||
173 | bitfield_length = idx + 1; | ||
174 | |||
175 | if (idx != id / (8 * sizeof(*bitfield))) | ||
176 | bitfield = drm_alloc(bitfield_length * | ||
177 | sizeof(*bitfield), DRM_MEM_BUFS); | ||
178 | |||
179 | if (!bitfield && bitfield_length) { | ||
180 | bitfield = dev->drw_bitfield; | ||
181 | bitfield_length = dev->drw_bitfield_length; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (bitfield != dev->drw_bitfield) { | ||
186 | info_length = 8 * sizeof(*bitfield) * bitfield_length; | ||
187 | |||
188 | info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); | ||
189 | |||
190 | if (!info && info_length) { | ||
191 | info = dev->drw_info; | ||
192 | info_length = dev->drw_info_length; | ||
193 | } | ||
194 | |||
195 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
196 | |||
197 | memcpy(bitfield, dev->drw_bitfield, bitfield_length * | ||
198 | sizeof(*bitfield)); | ||
199 | drm_free(dev->drw_bitfield, sizeof(*bitfield) * | ||
200 | dev->drw_bitfield_length, DRM_MEM_BUFS); | ||
201 | dev->drw_bitfield = bitfield; | ||
202 | dev->drw_bitfield_length = bitfield_length; | ||
203 | |||
204 | if (info != dev->drw_info) { | ||
205 | memcpy(info, dev->drw_info, info_length * | ||
206 | sizeof(*info)); | ||
207 | drm_free(dev->drw_info, sizeof(*info) * | ||
208 | dev->drw_info_length, DRM_MEM_BUFS); | ||
209 | dev->drw_info = info; | ||
210 | dev->drw_info_length = info_length; | ||
211 | } | ||
212 | |||
213 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
214 | } | ||
215 | |||
216 | DRM_DEBUG("%d\n", draw.handle); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { | ||
221 | DRM_DEVICE; | ||
222 | drm_update_draw_t update; | ||
223 | unsigned int id, idx, shift; | ||
224 | u32 *bitfield = dev->drw_bitfield; | ||
225 | unsigned long irqflags, bitfield_length = dev->drw_bitfield_length; | ||
226 | drm_drawable_info_t *info; | ||
227 | drm_clip_rect_t *rects; | ||
228 | int err; | ||
229 | |||
230 | DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, | ||
231 | sizeof(update)); | ||
232 | |||
233 | id = update.handle - 1; | ||
234 | idx = id / (8 * sizeof(*bitfield)); | ||
235 | shift = id % (8 * sizeof(*bitfield)); | ||
236 | |||
237 | if (idx < 0 || idx >= bitfield_length || | ||
238 | !(bitfield[idx] & (1 << shift))) { | ||
239 | DRM_ERROR("No such drawable %d\n", update.handle); | ||
240 | return DRM_ERR(EINVAL); | ||
241 | } | ||
242 | |||
243 | info = dev->drw_info[id]; | ||
244 | |||
245 | if (!info) { | ||
246 | info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); | ||
247 | |||
248 | if (!info) { | ||
249 | DRM_ERROR("Failed to allocate drawable info memory\n"); | ||
250 | return DRM_ERR(ENOMEM); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | switch (update.type) { | ||
255 | case DRM_DRAWABLE_CLIPRECTS: | ||
256 | if (update.num != info->num_rects) { | ||
257 | rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), | ||
258 | DRM_MEM_BUFS); | ||
259 | } else | ||
260 | rects = info->rects; | ||
261 | |||
262 | if (update.num && !rects) { | ||
263 | DRM_ERROR("Failed to allocate cliprect memory\n"); | ||
264 | err = DRM_ERR(ENOMEM); | ||
265 | goto error; | ||
266 | } | ||
267 | |||
268 | if (update.num && DRM_COPY_FROM_USER(rects, | ||
269 | (drm_clip_rect_t __user *) | ||
270 | (unsigned long)update.data, | ||
271 | update.num * | ||
272 | sizeof(*rects))) { | ||
273 | DRM_ERROR("Failed to copy cliprects from userspace\n"); | ||
274 | err = DRM_ERR(EFAULT); | ||
275 | goto error; | ||
276 | } | ||
277 | |||
278 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
279 | |||
280 | if (rects != info->rects) { | ||
281 | drm_free(info->rects, info->num_rects * | ||
282 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | ||
283 | } | ||
284 | |||
285 | info->rects = rects; | ||
286 | info->num_rects = update.num; | ||
287 | dev->drw_info[id] = info; | ||
288 | |||
289 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
290 | |||
291 | DRM_DEBUG("Updated %d cliprects for drawable %d\n", | ||
292 | info->num_rects, id); | ||
293 | break; | ||
294 | default: | ||
295 | DRM_ERROR("Invalid update type %d\n", update.type); | ||
296 | return DRM_ERR(EINVAL); | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | |||
301 | error: | ||
302 | if (!dev->drw_info[id]) | ||
303 | drm_free(info, sizeof(*info), DRM_MEM_BUFS); | ||
304 | else if (rects != dev->drw_info[id]->rects) | ||
305 | drm_free(rects, update.num * | ||
306 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | ||
307 | |||
308 | return err; | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * Caller must hold the drawable spinlock! | ||
313 | */ | ||
314 | drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { | ||
315 | u32 *bitfield = dev->drw_bitfield; | ||
316 | unsigned int idx, shift; | ||
317 | |||
318 | id--; | ||
319 | idx = id / (8 * sizeof(*bitfield)); | ||
320 | shift = id % (8 * sizeof(*bitfield)); | ||
321 | |||
322 | if (idx < 0 || idx >= dev->drw_bitfield_length || | ||
323 | !(bitfield[idx] & (1 << shift))) { | ||
324 | DRM_DEBUG("No such drawable %d\n", id); | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
328 | return dev->drw_info[id]; | ||
56 | } | 329 | } |
330 | EXPORT_SYMBOL(drm_get_drawable_info); | ||