diff options
Diffstat (limited to 'drivers/char/drm/drm_drawable.c')
-rw-r--r-- | drivers/char/drm/drm_drawable.c | 230 |
1 files changed, 222 insertions, 8 deletions
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c index 7857453c4f48..e5f97def26bf 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 | /* |
@@ -36,21 +37,234 @@ | |||
36 | #include "drmP.h" | 37 | #include "drmP.h" |
37 | 38 | ||
38 | /** No-op. */ | 39 | /** No-op. */ |
39 | int drm_adddraw(struct inode *inode, struct file *filp, | 40 | int drm_adddraw(DRM_IOCTL_ARGS) |
40 | unsigned int cmd, unsigned long arg) | ||
41 | { | 41 | { |
42 | DRM_DEVICE; | ||
43 | unsigned long irqflags; | ||
44 | int i, j = 0; | ||
42 | drm_draw_t draw; | 45 | drm_draw_t draw; |
43 | 46 | ||
44 | draw.handle = 0; /* NOOP */ | 47 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
48 | |||
49 | for (i = 0; i < dev->drw_bitfield_length; i++) { | ||
50 | u32 bitfield = dev->drw_bitfield[i]; | ||
51 | |||
52 | if (bitfield == ~0) | ||
53 | continue; | ||
54 | |||
55 | for (; j < sizeof(bitfield); j++) | ||
56 | if (!(bitfield & (1 << j))) | ||
57 | goto done; | ||
58 | } | ||
59 | done: | ||
60 | |||
61 | if (i == dev->drw_bitfield_length) { | ||
62 | u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, | ||
63 | (i + 1) * 4, DRM_MEM_BUFS); | ||
64 | |||
65 | if (!new_bitfield) { | ||
66 | DRM_ERROR("Failed to allocate new drawable bitfield\n"); | ||
67 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
68 | return DRM_ERR(ENOMEM); | ||
69 | } | ||
70 | |||
71 | if (32 * (i + 1) > dev->drw_info_length) { | ||
72 | void *new_info = drm_realloc(dev->drw_info, | ||
73 | dev->drw_info_length * | ||
74 | sizeof(drm_drawable_info_t*), | ||
75 | 32 * (i + 1) * | ||
76 | sizeof(drm_drawable_info_t*), | ||
77 | DRM_MEM_BUFS); | ||
78 | |||
79 | if (!new_info) { | ||
80 | DRM_ERROR("Failed to allocate new drawable info" | ||
81 | " array\n"); | ||
82 | |||
83 | drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); | ||
84 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
85 | return DRM_ERR(ENOMEM); | ||
86 | } | ||
87 | |||
88 | dev->drw_info = (drm_drawable_info_t**)new_info; | ||
89 | } | ||
90 | |||
91 | new_bitfield[i] = 0; | ||
92 | |||
93 | dev->drw_bitfield = new_bitfield; | ||
94 | dev->drw_bitfield_length++; | ||
95 | } | ||
96 | |||
97 | dev->drw_bitfield[i] |= 1 << j; | ||
98 | |||
99 | draw.handle = i * sizeof(u32) + j; | ||
45 | DRM_DEBUG("%d\n", draw.handle); | 100 | DRM_DEBUG("%d\n", draw.handle); |
46 | if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw))) | 101 | |
47 | return -EFAULT; | 102 | dev->drw_info[draw.handle] = NULL; |
103 | |||
104 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
105 | |||
106 | DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); | ||
107 | |||
48 | return 0; | 108 | return 0; |
49 | } | 109 | } |
50 | 110 | ||
51 | /** No-op. */ | 111 | /** No-op. */ |
52 | int drm_rmdraw(struct inode *inode, struct file *filp, | 112 | int drm_rmdraw(DRM_IOCTL_ARGS) |
53 | unsigned int cmd, unsigned long arg) | ||
54 | { | 113 | { |
55 | return 0; /* NOOP */ | 114 | DRM_DEVICE; |
115 | drm_draw_t draw; | ||
116 | unsigned int idx, mod; | ||
117 | unsigned long irqflags; | ||
118 | |||
119 | DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, | ||
120 | sizeof(draw)); | ||
121 | |||
122 | idx = draw.handle / 32; | ||
123 | mod = draw.handle % 32; | ||
124 | |||
125 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
126 | |||
127 | if (idx >= dev->drw_bitfield_length || | ||
128 | !(dev->drw_bitfield[idx] & (1 << mod))) { | ||
129 | DRM_DEBUG("No such drawable %d\n", draw.handle); | ||
130 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | dev->drw_bitfield[idx] &= ~(1 << mod); | ||
135 | |||
136 | if (idx == (dev->drw_bitfield_length - 1)) { | ||
137 | while (idx >= 0 && !dev->drw_bitfield[idx]) | ||
138 | --idx; | ||
139 | |||
140 | if (idx != draw.handle / 32) { | ||
141 | u32 *new_bitfield = drm_realloc(dev->drw_bitfield, | ||
142 | dev->drw_bitfield_length * 4, | ||
143 | (idx + 1) * 4, | ||
144 | DRM_MEM_BUFS); | ||
145 | |||
146 | if (new_bitfield || idx == -1) { | ||
147 | dev->drw_bitfield = new_bitfield; | ||
148 | dev->drw_bitfield_length = idx + 1; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | if (32 * dev->drw_bitfield_length < dev->drw_info_length) { | ||
154 | void *new_info = drm_realloc(dev->drw_info, | ||
155 | dev->drw_info_length * | ||
156 | sizeof(drm_drawable_info_t*), | ||
157 | 32 * dev->drw_bitfield_length * | ||
158 | sizeof(drm_drawable_info_t*), | ||
159 | DRM_MEM_BUFS); | ||
160 | |||
161 | if (new_info || !dev->drw_bitfield_length) { | ||
162 | dev->drw_info = (drm_drawable_info_t**)new_info; | ||
163 | dev->drw_info_length = 32 * dev->drw_bitfield_length; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
168 | |||
169 | DRM_DEBUG("%d\n", draw.handle); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | int drm_update_drawable_info(DRM_IOCTL_ARGS) { | ||
174 | DRM_DEVICE; | ||
175 | drm_update_draw_t update; | ||
176 | unsigned int id, idx, mod; | ||
177 | unsigned long irqflags; | ||
178 | drm_drawable_info_t *info; | ||
179 | void *new_data; | ||
180 | |||
181 | DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, | ||
182 | sizeof(update)); | ||
183 | |||
184 | id = update.handle; | ||
185 | idx = id / 32; | ||
186 | mod = id % 32; | ||
187 | |||
188 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
189 | |||
190 | if (idx >= dev->drw_bitfield_length || | ||
191 | !(dev->drw_bitfield[idx] & (1 << mod))) { | ||
192 | DRM_ERROR("No such drawable %d\n", update.handle); | ||
193 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
194 | return DRM_ERR(EINVAL); | ||
195 | } | ||
196 | |||
197 | info = dev->drw_info[id]; | ||
198 | |||
199 | if (!info) { | ||
200 | info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); | ||
201 | |||
202 | if (!info) { | ||
203 | DRM_ERROR("Failed to allocate drawable info memory\n"); | ||
204 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
205 | return DRM_ERR(ENOMEM); | ||
206 | } | ||
207 | |||
208 | dev->drw_info[id] = info; | ||
209 | } | ||
210 | |||
211 | switch (update.type) { | ||
212 | case DRM_DRAWABLE_CLIPRECTS: | ||
213 | if (update.num != info->num_rects) { | ||
214 | new_data = drm_alloc(update.num * | ||
215 | sizeof(drm_clip_rect_t), | ||
216 | DRM_MEM_BUFS); | ||
217 | |||
218 | if (!new_data) { | ||
219 | DRM_ERROR("Can't allocate cliprect memory\n"); | ||
220 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
221 | return DRM_ERR(ENOMEM); | ||
222 | } | ||
223 | |||
224 | info->rects = new_data; | ||
225 | } | ||
226 | |||
227 | if (DRM_COPY_FROM_USER(info->rects, | ||
228 | (drm_clip_rect_t __user *) | ||
229 | (unsigned long)update.data, | ||
230 | update.num * sizeof(drm_clip_rect_t))) { | ||
231 | DRM_ERROR("Can't copy cliprects from userspace\n"); | ||
232 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
233 | return DRM_ERR(EFAULT); | ||
234 | } | ||
235 | |||
236 | if (update.num != info->num_rects) { | ||
237 | drm_free(info->rects, info->num_rects * | ||
238 | sizeof(drm_clip_rect_t), DRM_MEM_BUFS); | ||
239 | info->num_rects = update.num; | ||
240 | } | ||
241 | |||
242 | DRM_DEBUG("Updated %d cliprects for drawable %d\n", | ||
243 | info->num_rects, id); | ||
244 | break; | ||
245 | default: | ||
246 | DRM_ERROR("Invalid update type %d\n", update.type); | ||
247 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
248 | return DRM_ERR(EINVAL); | ||
249 | } | ||
250 | |||
251 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * Caller must hold the drawable spinlock! | ||
258 | */ | ||
259 | drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { | ||
260 | unsigned int idx = id / 32, mod = id % 32; | ||
261 | |||
262 | if (idx >= dev->drw_bitfield_length || | ||
263 | !(dev->drw_bitfield[idx] & (1 << mod))) { | ||
264 | DRM_DEBUG("No such drawable %d\n", id); | ||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | return dev->drw_info[id]; | ||
56 | } | 269 | } |
270 | EXPORT_SYMBOL(drm_get_drawable_info); | ||