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