diff options
| -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 4e5ce8f7d65e..c32a2a50bfa2 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 | /** |
