diff options
author | Michal Januszewski <spock@gentoo.org> | 2005-07-27 14:46:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-27 19:26:19 -0400 |
commit | 03e259a9cdbd0583e71468293aaa1ccadbdaeff1 (patch) | |
tree | ee41f6bcfbeeeb6f3cd269622d499ee9eb6df233 | |
parent | dbd4f12859307c20a4c65a7de4cdd5f9f518dc7a (diff) |
[PATCH] fbdev: update info->cmap when setting cmap from user-/kernelspace.
The fb_info struct, as defined in include/linux/fb.h, contains an element
that is supposed to hold the current color map:
struct fb_cmap cmap; /* Current cmap */
This cmap is currently never updated when either fb_set_cmap() or
fb_set_user_cmap() are called. As a result, info->cmap contains the
default cmap that was set by a device driver/fbcon and a userspace
application using the FBIOGETCMAP ioctl will not always get the *currently*
used color map.
The patch fixes this by making sure the cmap is copied to info->cmap after
it is set correctly. It moves most of the code that is responsible for
setting the cmap to fb_set_cmap() and out of fb_set_user_cmap() to avoid
code-duplication.
Signed-off-by: Michal Januszewski <spock@gentoo.org>
Cc: <linux-fbdev-devel@lists.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/video/fbcmap.c | 96 |
1 files changed, 36 insertions, 60 deletions
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 4e5ce8f7d65..c32a2a50bfa 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c | |||
@@ -212,7 +212,7 @@ int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to) | |||
212 | 212 | ||
213 | int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) | 213 | int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) |
214 | { | 214 | { |
215 | int i, start; | 215 | int i, start, rc = 0; |
216 | u16 *red, *green, *blue, *transp; | 216 | u16 *red, *green, *blue, *transp; |
217 | u_int hred, hgreen, hblue, htransp = 0xffff; | 217 | u_int hred, hgreen, hblue, htransp = 0xffff; |
218 | 218 | ||
@@ -225,75 +225,51 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) | |||
225 | if (start < 0 || (!info->fbops->fb_setcolreg && | 225 | if (start < 0 || (!info->fbops->fb_setcolreg && |
226 | !info->fbops->fb_setcmap)) | 226 | !info->fbops->fb_setcmap)) |
227 | return -EINVAL; | 227 | return -EINVAL; |
228 | if (info->fbops->fb_setcmap) | 228 | if (info->fbops->fb_setcmap) { |
229 | return info->fbops->fb_setcmap(cmap, info); | 229 | rc = info->fbops->fb_setcmap(cmap, info); |
230 | for (i = 0; i < cmap->len; i++) { | 230 | } else { |
231 | hred = *red++; | 231 | for (i = 0; i < cmap->len; i++) { |
232 | hgreen = *green++; | 232 | hred = *red++; |
233 | hblue = *blue++; | 233 | hgreen = *green++; |
234 | if (transp) | 234 | hblue = *blue++; |
235 | htransp = *transp++; | 235 | if (transp) |
236 | if (info->fbops->fb_setcolreg(start++, | 236 | htransp = *transp++; |
237 | hred, hgreen, hblue, htransp, | 237 | if (info->fbops->fb_setcolreg(start++, |
238 | info)) | 238 | hred, hgreen, hblue, |
239 | break; | 239 | htransp, info)) |
240 | break; | ||
241 | } | ||
240 | } | 242 | } |
241 | return 0; | 243 | if (rc == 0) |
244 | fb_copy_cmap(cmap, &info->cmap); | ||
245 | |||
246 | return rc; | ||
242 | } | 247 | } |
243 | 248 | ||
244 | int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) | 249 | int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) |
245 | { | 250 | { |
246 | int i, start; | 251 | int rc, size = cmap->len * sizeof(u16); |
247 | u16 __user *red, *green, *blue, *transp; | 252 | struct fb_cmap umap; |
248 | u_int hred, hgreen, hblue, htransp = 0xffff; | ||
249 | |||
250 | red = cmap->red; | ||
251 | green = cmap->green; | ||
252 | blue = cmap->blue; | ||
253 | transp = cmap->transp; | ||
254 | start = cmap->start; | ||
255 | 253 | ||
256 | if (start < 0 || (!info->fbops->fb_setcolreg && | 254 | if (cmap->start < 0 || (!info->fbops->fb_setcolreg && |
257 | !info->fbops->fb_setcmap)) | 255 | !info->fbops->fb_setcmap)) |
258 | return -EINVAL; | 256 | return -EINVAL; |
259 | 257 | ||
260 | /* If we can batch, do it */ | 258 | memset(&umap, 0, sizeof(struct fb_cmap)); |
261 | if (info->fbops->fb_setcmap && cmap->len > 1) { | 259 | rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL); |
262 | struct fb_cmap umap; | 260 | if (rc) |
263 | int size = cmap->len * sizeof(u16); | ||
264 | int rc; | ||
265 | |||
266 | memset(&umap, 0, sizeof(struct fb_cmap)); | ||
267 | rc = fb_alloc_cmap(&umap, cmap->len, transp != NULL); | ||
268 | if (rc) | ||
269 | return rc; | ||
270 | if (copy_from_user(umap.red, red, size) || | ||
271 | copy_from_user(umap.green, green, size) || | ||
272 | copy_from_user(umap.blue, blue, size) || | ||
273 | (transp && copy_from_user(umap.transp, transp, size))) { | ||
274 | rc = -EFAULT; | ||
275 | } | ||
276 | umap.start = start; | ||
277 | if (rc == 0) | ||
278 | rc = info->fbops->fb_setcmap(&umap, info); | ||
279 | fb_dealloc_cmap(&umap); | ||
280 | return rc; | 261 | return rc; |
262 | if (copy_from_user(umap.red, cmap->red, size) || | ||
263 | copy_from_user(umap.green, cmap->green, size) || | ||
264 | copy_from_user(umap.blue, cmap->blue, size) || | ||
265 | (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) { | ||
266 | fb_dealloc_cmap(&umap); | ||
267 | return -EFAULT; | ||
281 | } | 268 | } |
282 | 269 | umap.start = cmap->start; | |
283 | for (i = 0; i < cmap->len; i++, red++, blue++, green++) { | 270 | rc = fb_set_cmap(&umap, info); |
284 | if (get_user(hred, red) || | 271 | fb_dealloc_cmap(&umap); |
285 | get_user(hgreen, green) || | 272 | return rc; |
286 | get_user(hblue, blue) || | ||
287 | (transp && get_user(htransp, transp))) | ||
288 | return -EFAULT; | ||
289 | if (info->fbops->fb_setcolreg(start++, | ||
290 | hred, hgreen, hblue, htransp, | ||
291 | info)) | ||
292 | return 0; | ||
293 | if (transp) | ||
294 | transp++; | ||
295 | } | ||
296 | return 0; | ||
297 | } | 273 | } |
298 | 274 | ||
299 | /** | 275 | /** |