Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
0003  *
0004  *  Created 15 Jun 1997 by Geert Uytterhoeven
0005  *
0006  *  2001 - Documented with DocBook
0007  *  - Brad Douglas <brad@neruo.com>
0008  *
0009  *  This file is subject to the terms and conditions of the GNU General Public
0010  *  License.  See the file COPYING in the main directory of this archive for
0011  *  more details.
0012  */
0013 
0014 #include <linux/string.h>
0015 #include <linux/module.h>
0016 #include <linux/fb.h>
0017 #include <linux/slab.h>
0018 #include <linux/uaccess.h>
0019 
0020 static u16 red2[] __read_mostly = {
0021     0x0000, 0xaaaa
0022 };
0023 static u16 green2[] __read_mostly = {
0024     0x0000, 0xaaaa
0025 };
0026 static u16 blue2[] __read_mostly = {
0027     0x0000, 0xaaaa
0028 };
0029 
0030 static u16 red4[] __read_mostly = {
0031     0x0000, 0xaaaa, 0x5555, 0xffff
0032 };
0033 static u16 green4[] __read_mostly = {
0034     0x0000, 0xaaaa, 0x5555, 0xffff
0035 };
0036 static u16 blue4[] __read_mostly = {
0037     0x0000, 0xaaaa, 0x5555, 0xffff
0038 };
0039 
0040 static u16 red8[] __read_mostly = {
0041     0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
0042 };
0043 static u16 green8[] __read_mostly = {
0044     0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
0045 };
0046 static u16 blue8[] __read_mostly = {
0047     0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
0048 };
0049 
0050 static u16 red16[] __read_mostly = {
0051     0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
0052     0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
0053 };
0054 static u16 green16[] __read_mostly = {
0055     0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
0056     0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
0057 };
0058 static u16 blue16[] __read_mostly = {
0059     0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
0060     0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
0061 };
0062 
0063 static const struct fb_cmap default_2_colors = {
0064     .len=2, .red=red2, .green=green2, .blue=blue2
0065 };
0066 static const struct fb_cmap default_8_colors = {
0067     .len=8, .red=red8, .green=green8, .blue=blue8
0068 };
0069 static const struct fb_cmap default_4_colors = {
0070     .len=4, .red=red4, .green=green4, .blue=blue4
0071 };
0072 static const struct fb_cmap default_16_colors = {
0073     .len=16, .red=red16, .green=green16, .blue=blue16
0074 };
0075 
0076 
0077 
0078 /**
0079  *  fb_alloc_cmap_gfp - allocate a colormap
0080  *  @cmap: frame buffer colormap structure
0081  *  @len: length of @cmap
0082  *  @transp: boolean, 1 if there is transparency, 0 otherwise
0083  *  @flags: flags for kmalloc memory allocation
0084  *
0085  *  Allocates memory for a colormap @cmap.  @len is the
0086  *  number of entries in the palette.
0087  *
0088  *  Returns negative errno on error, or zero on success.
0089  *
0090  */
0091 
0092 int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
0093 {
0094     int size = len * sizeof(u16);
0095     int ret = -ENOMEM;
0096 
0097     flags |= __GFP_NOWARN;
0098 
0099     if (cmap->len != len) {
0100         fb_dealloc_cmap(cmap);
0101         if (!len)
0102             return 0;
0103 
0104         cmap->red = kzalloc(size, flags);
0105         if (!cmap->red)
0106             goto fail;
0107         cmap->green = kzalloc(size, flags);
0108         if (!cmap->green)
0109             goto fail;
0110         cmap->blue = kzalloc(size, flags);
0111         if (!cmap->blue)
0112             goto fail;
0113         if (transp) {
0114             cmap->transp = kzalloc(size, flags);
0115             if (!cmap->transp)
0116                 goto fail;
0117         } else {
0118             cmap->transp = NULL;
0119         }
0120     }
0121     cmap->start = 0;
0122     cmap->len = len;
0123     ret = fb_copy_cmap(fb_default_cmap(len), cmap);
0124     if (ret)
0125         goto fail;
0126     return 0;
0127 
0128 fail:
0129     fb_dealloc_cmap(cmap);
0130     return ret;
0131 }
0132 
0133 int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
0134 {
0135     return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
0136 }
0137 
0138 /**
0139  *      fb_dealloc_cmap - deallocate a colormap
0140  *      @cmap: frame buffer colormap structure
0141  *
0142  *      Deallocates a colormap that was previously allocated with
0143  *      fb_alloc_cmap().
0144  *
0145  */
0146 
0147 void fb_dealloc_cmap(struct fb_cmap *cmap)
0148 {
0149     kfree(cmap->red);
0150     kfree(cmap->green);
0151     kfree(cmap->blue);
0152     kfree(cmap->transp);
0153 
0154     cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
0155     cmap->len = 0;
0156 }
0157 
0158 /**
0159  *  fb_copy_cmap - copy a colormap
0160  *  @from: frame buffer colormap structure
0161  *  @to: frame buffer colormap structure
0162  *
0163  *  Copy contents of colormap from @from to @to.
0164  */
0165 
0166 int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
0167 {
0168     unsigned int tooff = 0, fromoff = 0;
0169     size_t size;
0170 
0171     if (to->start > from->start)
0172         fromoff = to->start - from->start;
0173     else
0174         tooff = from->start - to->start;
0175     if (fromoff >= from->len || tooff >= to->len)
0176         return -EINVAL;
0177 
0178     size = min_t(size_t, to->len - tooff, from->len - fromoff);
0179     if (size == 0)
0180         return -EINVAL;
0181     size *= sizeof(u16);
0182 
0183     memcpy(to->red+tooff, from->red+fromoff, size);
0184     memcpy(to->green+tooff, from->green+fromoff, size);
0185     memcpy(to->blue+tooff, from->blue+fromoff, size);
0186     if (from->transp && to->transp)
0187         memcpy(to->transp+tooff, from->transp+fromoff, size);
0188     return 0;
0189 }
0190 
0191 int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
0192 {
0193     unsigned int tooff = 0, fromoff = 0;
0194     size_t size;
0195 
0196     if (to->start > from->start)
0197         fromoff = to->start - from->start;
0198     else
0199         tooff = from->start - to->start;
0200     if (fromoff >= from->len || tooff >= to->len)
0201         return -EINVAL;
0202 
0203     size = min_t(size_t, to->len - tooff, from->len - fromoff);
0204     if (size == 0)
0205         return -EINVAL;
0206     size *= sizeof(u16);
0207 
0208     if (copy_to_user(to->red+tooff, from->red+fromoff, size))
0209         return -EFAULT;
0210     if (copy_to_user(to->green+tooff, from->green+fromoff, size))
0211         return -EFAULT;
0212     if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
0213         return -EFAULT;
0214     if (from->transp && to->transp)
0215         if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
0216             return -EFAULT;
0217     return 0;
0218 }
0219 
0220 /**
0221  *  fb_set_cmap - set the colormap
0222  *  @cmap: frame buffer colormap structure
0223  *  @info: frame buffer info structure
0224  *
0225  *  Sets the colormap @cmap for a screen of device @info.
0226  *
0227  *  Returns negative errno on error, or zero on success.
0228  *
0229  */
0230 
0231 int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
0232 {
0233     int i, start, rc = 0;
0234     u16 *red, *green, *blue, *transp;
0235     u_int hred, hgreen, hblue, htransp = 0xffff;
0236 
0237     red = cmap->red;
0238     green = cmap->green;
0239     blue = cmap->blue;
0240     transp = cmap->transp;
0241     start = cmap->start;
0242 
0243     if (start < 0 || (!info->fbops->fb_setcolreg &&
0244               !info->fbops->fb_setcmap))
0245         return -EINVAL;
0246     if (info->fbops->fb_setcmap) {
0247         rc = info->fbops->fb_setcmap(cmap, info);
0248     } else {
0249         for (i = 0; i < cmap->len; i++) {
0250             hred = *red++;
0251             hgreen = *green++;
0252             hblue = *blue++;
0253             if (transp)
0254                 htransp = *transp++;
0255             if (info->fbops->fb_setcolreg(start++,
0256                               hred, hgreen, hblue,
0257                               htransp, info))
0258                 break;
0259         }
0260     }
0261     if (rc == 0)
0262         fb_copy_cmap(cmap, &info->cmap);
0263 
0264     return rc;
0265 }
0266 
0267 int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
0268 {
0269     int rc, size = cmap->len * sizeof(u16);
0270     struct fb_cmap umap;
0271 
0272     if (size < 0 || size < cmap->len)
0273         return -E2BIG;
0274 
0275     memset(&umap, 0, sizeof(struct fb_cmap));
0276     rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
0277                 GFP_KERNEL);
0278     if (rc)
0279         return rc;
0280     if (copy_from_user(umap.red, cmap->red, size) ||
0281         copy_from_user(umap.green, cmap->green, size) ||
0282         copy_from_user(umap.blue, cmap->blue, size) ||
0283         (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) {
0284         rc = -EFAULT;
0285         goto out;
0286     }
0287     umap.start = cmap->start;
0288     lock_fb_info(info);
0289     rc = fb_set_cmap(&umap, info);
0290     unlock_fb_info(info);
0291 out:
0292     fb_dealloc_cmap(&umap);
0293     return rc;
0294 }
0295 
0296 /**
0297  *  fb_default_cmap - get default colormap
0298  *  @len: size of palette for a depth
0299  *
0300  *  Gets the default colormap for a specific screen depth.  @len
0301  *  is the size of the palette for a particular screen depth.
0302  *
0303  *  Returns pointer to a frame buffer colormap structure.
0304  *
0305  */
0306 
0307 const struct fb_cmap *fb_default_cmap(int len)
0308 {
0309     if (len <= 2)
0310     return &default_2_colors;
0311     if (len <= 4)
0312     return &default_4_colors;
0313     if (len <= 8)
0314     return &default_8_colors;
0315     return &default_16_colors;
0316 }
0317 
0318 
0319 /**
0320  *  fb_invert_cmaps - invert all defaults colormaps
0321  *
0322  *  Invert all default colormaps.
0323  *
0324  */
0325 
0326 void fb_invert_cmaps(void)
0327 {
0328     u_int i;
0329 
0330     for (i = 0; i < ARRAY_SIZE(red2); i++) {
0331     red2[i] = ~red2[i];
0332     green2[i] = ~green2[i];
0333     blue2[i] = ~blue2[i];
0334     }
0335     for (i = 0; i < ARRAY_SIZE(red4); i++) {
0336     red4[i] = ~red4[i];
0337     green4[i] = ~green4[i];
0338     blue4[i] = ~blue4[i];
0339     }
0340     for (i = 0; i < ARRAY_SIZE(red8); i++) {
0341     red8[i] = ~red8[i];
0342     green8[i] = ~green8[i];
0343     blue8[i] = ~blue8[i];
0344     }
0345     for (i = 0; i < ARRAY_SIZE(red16); i++) {
0346     red16[i] = ~red16[i];
0347     green16[i] = ~green16[i];
0348     blue16[i] = ~blue16[i];
0349     }
0350 }
0351 
0352 
0353     /*
0354      *  Visible symbols for modules
0355      */
0356 
0357 EXPORT_SYMBOL(fb_alloc_cmap);
0358 EXPORT_SYMBOL(fb_dealloc_cmap);
0359 EXPORT_SYMBOL(fb_copy_cmap);
0360 EXPORT_SYMBOL(fb_set_cmap);
0361 EXPORT_SYMBOL(fb_default_cmap);
0362 EXPORT_SYMBOL(fb_invert_cmaps);