Line data Source code
1 : /*
2 : * linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
3 : *
4 : * Created 15 Jun 1997 by Geert Uytterhoeven
5 : *
6 : * 2001 - Documented with DocBook
7 : * - Brad Douglas <brad@neruo.com>
8 : *
9 : * This file is subject to the terms and conditions of the GNU General Public
10 : * License. See the file COPYING in the main directory of this archive for
11 : * more details.
12 : */
13 :
14 : #include <linux/string.h>
15 : #include <linux/module.h>
16 : #include <linux/fb.h>
17 : #include <linux/slab.h>
18 : #include <linux/uaccess.h>
19 :
20 1 : static u16 red2[] __read_mostly = {
21 : 0x0000, 0xaaaa
22 : };
23 1 : static u16 green2[] __read_mostly = {
24 : 0x0000, 0xaaaa
25 : };
26 1 : static u16 blue2[] __read_mostly = {
27 : 0x0000, 0xaaaa
28 : };
29 :
30 1 : static u16 red4[] __read_mostly = {
31 : 0x0000, 0xaaaa, 0x5555, 0xffff
32 : };
33 1 : static u16 green4[] __read_mostly = {
34 : 0x0000, 0xaaaa, 0x5555, 0xffff
35 : };
36 1 : static u16 blue4[] __read_mostly = {
37 : 0x0000, 0xaaaa, 0x5555, 0xffff
38 : };
39 :
40 1 : static u16 red8[] __read_mostly = {
41 : 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
42 : };
43 1 : static u16 green8[] __read_mostly = {
44 : 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
45 : };
46 1 : static u16 blue8[] __read_mostly = {
47 : 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
48 : };
49 :
50 1 : static u16 red16[] __read_mostly = {
51 : 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
52 : 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
53 : };
54 1 : static u16 green16[] __read_mostly = {
55 : 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
56 : 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
57 : };
58 1 : static u16 blue16[] __read_mostly = {
59 : 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
60 : 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
61 : };
62 :
63 1 : static const struct fb_cmap default_2_colors = {
64 : .len=2, .red=red2, .green=green2, .blue=blue2
65 : };
66 1 : static const struct fb_cmap default_8_colors = {
67 : .len=8, .red=red8, .green=green8, .blue=blue8
68 : };
69 1 : static const struct fb_cmap default_4_colors = {
70 : .len=4, .red=red4, .green=green4, .blue=blue4
71 : };
72 1 : static const struct fb_cmap default_16_colors = {
73 : .len=16, .red=red16, .green=green16, .blue=blue16
74 : };
75 :
76 :
77 :
78 : /**
79 : * fb_alloc_cmap - allocate a colormap
80 : * @cmap: frame buffer colormap structure
81 : * @len: length of @cmap
82 : * @transp: boolean, 1 if there is transparency, 0 otherwise
83 : *
84 : * Allocates memory for a colormap @cmap. @len is the
85 : * number of entries in the palette.
86 : *
87 : * Returns negative errno on error, or zero on success.
88 : *
89 : */
90 :
91 : int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
92 : {
93 10 : int size = len*sizeof(u16);
94 5 :
95 15 : if (cmap->len != len) {
96 15 : fb_dealloc_cmap(cmap);
97 15 : if (!len)
98 10 : return 0;
99 35 : if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
100 10 : goto fail;
101 35 : if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
102 10 : goto fail;
103 30 : if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
104 5 : goto fail;
105 10 : if (transp) {
106 30 : if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
107 5 : goto fail;
108 : } else
109 5 : cmap->transp = NULL;
110 : }
111 15 : cmap->start = 0;
112 15 : cmap->len = len;
113 40 : fb_copy_cmap(fb_default_cmap(len), cmap);
114 5 : return 0;
115 20 :
116 : fail:
117 40 : fb_dealloc_cmap(cmap);
118 5 : return -ENOMEM;
119 : }
120 :
121 : /**
122 : * fb_dealloc_cmap - deallocate a colormap
123 : * @cmap: frame buffer colormap structure
124 : *
125 : * Deallocates a colormap that was previously allocated with
126 : * fb_alloc_cmap().
127 : *
128 : */
129 :
130 : void fb_dealloc_cmap(struct fb_cmap *cmap)
131 : {
132 165 : kfree(cmap->red);
133 165 : kfree(cmap->green);
134 165 : kfree(cmap->blue);
135 110 : kfree(cmap->transp);
136 :
137 385 : cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
138 55 : cmap->len = 0;
139 55 : }
140 :
141 : /**
142 : * fb_copy_cmap - copy a colormap
143 : * @from: frame buffer colormap structure
144 : * @to: frame buffer colormap structure
145 : *
146 : * Copy contents of colormap from @from to @to.
147 : */
148 :
149 : int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
150 : {
151 117 : int tooff = 0, fromoff = 0;
152 39 : int size;
153 39 :
154 117 : if (to->start > from->start)
155 78 : fromoff = to->start - from->start;
156 : else
157 78 : tooff = from->start - to->start;
158 39 : size = to->len - tooff;
159 117 : if (size > (int) (from->len - fromoff))
160 78 : size = from->len - fromoff;
161 78 : if (size <= 0)
162 39 : return -EINVAL;
163 39 : size *= sizeof(u16);
164 :
165 39 : memcpy(to->red+tooff, from->red+fromoff, size);
166 39 : memcpy(to->green+tooff, from->green+fromoff, size);
167 39 : memcpy(to->blue+tooff, from->blue+fromoff, size);
168 234 : if (from->transp && to->transp)
169 39 : memcpy(to->transp+tooff, from->transp+fromoff, size);
170 39 : return 0;
171 : }
172 :
173 : int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
174 : {
175 15 : int tooff = 0, fromoff = 0;
176 5 : int size;
177 5 :
178 20 : if (to->start > from->start)
179 15 : fromoff = to->start - from->start;
180 5 : else
181 15 : tooff = from->start - to->start;
182 5 : size = to->len - tooff;
183 15 : if (size > (int) (from->len - fromoff))
184 10 : size = from->len - fromoff;
185 10 : if (size <= 0)
186 5 : return -EINVAL;
187 5 : size *= sizeof(u16);
188 :
189 20 : if (copy_to_user(to->red+tooff, from->red+fromoff, size))
190 5 : return -EFAULT;
191 20 : if (copy_to_user(to->green+tooff, from->green+fromoff, size))
192 5 : return -EFAULT;
193 20 : if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
194 5 : return -EFAULT;
195 30 : if (from->transp && to->transp)
196 20 : if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
197 5 : return -EFAULT;
198 10 : return 0;
199 : }
200 :
201 : /**
202 : * fb_set_cmap - set the colormap
203 : * @cmap: frame buffer colormap structure
204 : * @info: frame buffer info structure
205 : *
206 : * Sets the colormap @cmap for a screen of device @info.
207 : *
208 : * Returns negative errno on error, or zero on success.
209 : *
210 : */
211 :
212 : int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
213 : {
214 34 : int i, start, rc = 0;
215 17 : u16 *red, *green, *blue, *transp;
216 34 : u_int hred, hgreen, hblue, htransp = 0xffff;
217 17 :
218 34 : red = cmap->red;
219 34 : green = cmap->green;
220 34 : blue = cmap->blue;
221 34 : transp = cmap->transp;
222 51 : start = cmap->start;
223 17 :
224 153 : if (start < 0 || (!info->fbops->fb_setcolreg &&
225 17 : !info->fbops->fb_setcmap))
226 34 : return -EINVAL;
227 68 : if (info->fbops->fb_setcmap) {
228 34 : rc = info->fbops->fb_setcmap(cmap, info);
229 17 : } else {
230 102 : for (i = 0; i < cmap->len; i++) {
231 85 : hred = *red++;
232 68 : hgreen = *green++;
233 51 : hblue = *blue++;
234 34 : if (transp)
235 51 : htransp = *transp++;
236 102 : if (info->fbops->fb_setcolreg(start++,
237 : hred, hgreen, hblue,
238 : htransp, info))
239 17 : break;
240 : }
241 : }
242 68 : if (rc == 0)
243 68 : fb_copy_cmap(cmap, &info->cmap);
244 :
245 51 : return rc;
246 : }
247 :
248 : int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
249 : {
250 10 : int rc, size = cmap->len * sizeof(u16);
251 5 : struct fb_cmap umap;
252 5 :
253 10 : memset(&umap, 0, sizeof(struct fb_cmap));
254 35 : rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL);
255 15 : if (rc)
256 10 : return rc;
257 140 : if (copy_from_user(umap.red, cmap->red, size) ||
258 : copy_from_user(umap.green, cmap->green, size) ||
259 : copy_from_user(umap.blue, cmap->blue, size) ||
260 : (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) {
261 20 : rc = -EFAULT;
262 20 : goto out;
263 : }
264 10 : umap.start = cmap->start;
265 30 : if (!lock_fb_info(info)) {
266 5 : rc = -ENODEV;
267 5 : goto out;
268 : }
269 30 : if (cmap->start < 0 || (!info->fbops->fb_setcolreg &&
270 : !info->fbops->fb_setcmap)) {
271 5 : rc = -EINVAL;
272 5 : goto out1;
273 : }
274 20 : rc = fb_set_cmap(&umap, info);
275 : out1:
276 25 : unlock_fb_info(info);
277 : out:
278 65 : fb_dealloc_cmap(&umap);
279 5 : return rc;
280 : }
281 :
282 : /**
283 : * fb_default_cmap - get default colormap
284 : * @len: size of palette for a depth
285 : *
286 : * Gets the default colormap for a specific screen depth. @len
287 : * is the size of the palette for a particular screen depth.
288 : *
289 : * Returns pointer to a frame buffer colormap structure.
290 : *
291 : */
292 :
293 : const struct fb_cmap *fb_default_cmap(int len)
294 : {
295 30 : if (len <= 2)
296 15 : return &default_2_colors;
297 30 : if (len <= 4)
298 15 : return &default_4_colors;
299 30 : if (len <= 8)
300 15 : return &default_8_colors;
301 15 : return &default_16_colors;
302 : }
303 :
304 :
305 : /**
306 : * fb_invert_cmaps - invert all defaults colormaps
307 : *
308 : * Invert all default colormaps.
309 : *
310 : */
311 :
312 : void fb_invert_cmaps(void)
313 : {
314 0 : u_int i;
315 :
316 0 : for (i = 0; i < ARRAY_SIZE(red2); i++) {
317 0 : red2[i] = ~red2[i];
318 0 : green2[i] = ~green2[i];
319 0 : blue2[i] = ~blue2[i];
320 : }
321 0 : for (i = 0; i < ARRAY_SIZE(red4); i++) {
322 0 : red4[i] = ~red4[i];
323 0 : green4[i] = ~green4[i];
324 0 : blue4[i] = ~blue4[i];
325 : }
326 0 : for (i = 0; i < ARRAY_SIZE(red8); i++) {
327 0 : red8[i] = ~red8[i];
328 0 : green8[i] = ~green8[i];
329 0 : blue8[i] = ~blue8[i];
330 : }
331 0 : for (i = 0; i < ARRAY_SIZE(red16); i++) {
332 0 : red16[i] = ~red16[i];
333 0 : green16[i] = ~green16[i];
334 0 : blue16[i] = ~blue16[i];
335 : }
336 : }
337 :
338 0 :
339 : /*
340 : * Visible symbols for modules
341 : */
342 :
343 : EXPORT_SYMBOL(fb_alloc_cmap);
344 : EXPORT_SYMBOL(fb_dealloc_cmap);
345 : EXPORT_SYMBOL(fb_copy_cmap);
346 : EXPORT_SYMBOL(fb_set_cmap);
347 : EXPORT_SYMBOL(fb_default_cmap);
348 : EXPORT_SYMBOL(fb_invert_cmaps);
|