Commit | Line | Data |
---|---|---|
1da177e4 LT |
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); |