summaryrefslogtreecommitdiffstats
path: root/drivers/video/fbcmap.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-05-01 08:59:22 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 08:59:22 -0700
commit7149437669f79b497830e643a2b13d26a017b038 (patch)
treef5df8234c2e3cca1a335cf64b9f387c98c123fcf /drivers/video/fbcmap.c
parent5b052d8bb3ad9108489e7475868e14372774ca08 (diff)
downloadlinux-7149437669f79b497830e643a2b13d26a017b038.tar.bz2
[PATCH] fbdev: Batch cmap changes at driver level
This patch adds to the fbdev interface a set_cmap callback that allow the driver to "batch" palette changes. This is useful for drivers like radeonfb which might require lenghtly workarounds on palette accesses, thus allowing to factor out those workarounds efficiently. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/fbcmap.c')
-rw-r--r--drivers/video/fbcmap.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index c51f8fb5c1de..4e5ce8f7d65e 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -222,8 +222,11 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
transp = cmap->transp;
start = cmap->start;
- if (start < 0 || !info->fbops->fb_setcolreg)
+ if (start < 0 || (!info->fbops->fb_setcolreg &&
+ !info->fbops->fb_setcmap))
return -EINVAL;
+ if (info->fbops->fb_setcmap)
+ return info->fbops->fb_setcmap(cmap, info);
for (i = 0; i < cmap->len; i++) {
hred = *red++;
hgreen = *green++;
@@ -250,8 +253,33 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
transp = cmap->transp;
start = cmap->start;
- if (start < 0 || !info->fbops->fb_setcolreg)
+ if (start < 0 || (!info->fbops->fb_setcolreg &&
+ !info->fbops->fb_setcmap))
return -EINVAL;
+
+ /* If we can batch, do it */
+ if (info->fbops->fb_setcmap && cmap->len > 1) {
+ struct fb_cmap umap;
+ int size = cmap->len * sizeof(u16);
+ int rc;
+
+ memset(&umap, 0, sizeof(struct fb_cmap));
+ rc = fb_alloc_cmap(&umap, cmap->len, transp != NULL);
+ if (rc)
+ return rc;
+ if (copy_from_user(umap.red, red, size) ||
+ copy_from_user(umap.green, green, size) ||
+ copy_from_user(umap.blue, blue, size) ||
+ (transp && copy_from_user(umap.transp, transp, size))) {
+ rc = -EFAULT;
+ }
+ umap.start = start;
+ if (rc == 0)
+ rc = info->fbops->fb_setcmap(&umap, info);
+ fb_dealloc_cmap(&umap);
+ return rc;
+ }
+
for (i = 0; i < cmap->len; i++, red++, blue++, green++) {
if (get_user(hred, red) ||
get_user(hgreen, green) ||