Blame view

drivers/video/fbcmap.c 8.46 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   *  linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
   *
   *	Created 15 Jun 1997 by Geert Uytterhoeven
   *
   *	2001 - Documented with DocBook
   *	- Brad Douglas <brad@neruo.com>
   *
   *  This file is subject to the terms and conditions of the GNU General Public
   *  License.  See the file COPYING in the main directory of this archive for
   *  more details.
   */
  
  #include <linux/string.h>
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <linux/fb.h>
  #include <linux/slab.h>
84902b7af   Krzysztof Helt   fbdev: change asm...
18
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
20
  static u16 red2[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
      0x0000, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
23
  static u16 green2[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
      0x0000, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
26
  static u16 blue2[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
      0x0000, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
29
  static u16 red4[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
      0x0000, 0xaaaa, 0x5555, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
32
  static u16 green4[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
      0x0000, 0xaaaa, 0x5555, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
35
  static u16 blue4[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
      0x0000, 0xaaaa, 0x5555, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
38
  static u16 red8[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
      0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
41
  static u16 green8[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
      0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
44
  static u16 blue8[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
      0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
47
  static u16 red16[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
      0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
      0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
51
  static u16 green16[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
      0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
      0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
55
  static u16 blue16[] __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
      0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
      0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
59
60
  static const struct fb_cmap default_2_colors = {
      .len=2, .red=red2, .green=green2, .blue=blue2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
62
63
  static const struct fb_cmap default_8_colors = {
      .len=8, .red=red8, .green=green8, .blue=blue8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
65
66
  static const struct fb_cmap default_4_colors = {
      .len=4, .red=red4, .green=green4, .blue=blue4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
68
69
  static const struct fb_cmap default_16_colors = {
      .len=16, .red=red16, .green=green16, .blue=blue16
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  };
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
71

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
  /**
   *	fb_alloc_cmap - allocate a colormap
   *	@cmap: frame buffer colormap structure
   *	@len: length of @cmap
   *	@transp: boolean, 1 if there is transparency, 0 otherwise
22a95949d   Randy Dunlap   framebuffer: fix ...
77
   *	@flags: flags for kmalloc memory allocation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
   *
   *	Allocates memory for a colormap @cmap.  @len is the
   *	number of entries in the palette.
   *
db77ec270   Alan Curry   [PATCH] framebuff...
82
   *	Returns negative errno on error, or zero on success.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
   *
   */
1e7c78048   Dan Carpenter   fbcmap: integer o...
85
  int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  {
c353103de   Dan Carpenter   fbcmap: cleanup w...
87
  	int size = len * sizeof(u16);
1e7c78048   Dan Carpenter   fbcmap: integer o...
88
  	int ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

c353103de   Dan Carpenter   fbcmap: cleanup w...
90
91
92
93
  	if (cmap->len != len) {
  		fb_dealloc_cmap(cmap);
  		if (!len)
  			return 0;
1e7c78048   Dan Carpenter   fbcmap: integer o...
94
  		cmap->red = kmalloc(size, flags);
c353103de   Dan Carpenter   fbcmap: cleanup w...
95
96
  		if (!cmap->red)
  			goto fail;
1e7c78048   Dan Carpenter   fbcmap: integer o...
97
  		cmap->green = kmalloc(size, flags);
c353103de   Dan Carpenter   fbcmap: cleanup w...
98
99
  		if (!cmap->green)
  			goto fail;
1e7c78048   Dan Carpenter   fbcmap: integer o...
100
  		cmap->blue = kmalloc(size, flags);
c353103de   Dan Carpenter   fbcmap: cleanup w...
101
102
103
  		if (!cmap->blue)
  			goto fail;
  		if (transp) {
1e7c78048   Dan Carpenter   fbcmap: integer o...
104
  			cmap->transp = kmalloc(size, flags);
c353103de   Dan Carpenter   fbcmap: cleanup w...
105
106
107
108
109
110
111
112
  			if (!cmap->transp)
  				goto fail;
  		} else {
  			cmap->transp = NULL;
  		}
  	}
  	cmap->start = 0;
  	cmap->len = len;
1e7c78048   Dan Carpenter   fbcmap: integer o...
113
114
115
  	ret = fb_copy_cmap(fb_default_cmap(len), cmap);
  	if (ret)
  		goto fail;
c353103de   Dan Carpenter   fbcmap: cleanup w...
116
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
  
  fail:
c353103de   Dan Carpenter   fbcmap: cleanup w...
119
  	fb_dealloc_cmap(cmap);
1e7c78048   Dan Carpenter   fbcmap: integer o...
120
121
122
123
124
125
  	return ret;
  }
  
  int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
  {
  	return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  }
  
  /**
   *      fb_dealloc_cmap - deallocate a colormap
   *      @cmap: frame buffer colormap structure
   *
   *      Deallocates a colormap that was previously allocated with
   *      fb_alloc_cmap().
   *
   */
  
  void fb_dealloc_cmap(struct fb_cmap *cmap)
  {
  	kfree(cmap->red);
  	kfree(cmap->green);
  	kfree(cmap->blue);
  	kfree(cmap->transp);
  
  	cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
  	cmap->len = 0;
  }
  
  /**
   *	fb_copy_cmap - copy a colormap
   *	@from: frame buffer colormap structure
   *	@to: frame buffer colormap structure
   *
   *	Copy contents of colormap from @from to @to.
   */
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
155
  int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  {
  	int tooff = 0, fromoff = 0;
  	int size;
  
  	if (to->start > from->start)
  		fromoff = to->start - from->start;
  	else
  		tooff = from->start - to->start;
  	size = to->len - tooff;
  	if (size > (int) (from->len - fromoff))
  		size = from->len - fromoff;
  	if (size <= 0)
  		return -EINVAL;
  	size *= sizeof(u16);
  
  	memcpy(to->red+tooff, from->red+fromoff, size);
  	memcpy(to->green+tooff, from->green+fromoff, size);
  	memcpy(to->blue+tooff, from->blue+fromoff, size);
  	if (from->transp && to->transp)
  		memcpy(to->transp+tooff, from->transp+fromoff, size);
  	return 0;
  }
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
178
  int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  {
  	int tooff = 0, fromoff = 0;
  	int size;
  
  	if (to->start > from->start)
  		fromoff = to->start - from->start;
  	else
  		tooff = from->start - to->start;
  	size = to->len - tooff;
  	if (size > (int) (from->len - fromoff))
  		size = from->len - fromoff;
  	if (size <= 0)
  		return -EINVAL;
  	size *= sizeof(u16);
  
  	if (copy_to_user(to->red+tooff, from->red+fromoff, size))
  		return -EFAULT;
  	if (copy_to_user(to->green+tooff, from->green+fromoff, size))
  		return -EFAULT;
  	if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
  		return -EFAULT;
  	if (from->transp && to->transp)
  		if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
  			return -EFAULT;
  	return 0;
  }
  
  /**
   *	fb_set_cmap - set the colormap
   *	@cmap: frame buffer colormap structure
   *	@info: frame buffer info structure
   *
   *	Sets the colormap @cmap for a screen of device @info.
   *
   *	Returns negative errno on error, or zero on success.
   *
   */
  
  int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
  {
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
219
  	int i, start, rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
227
  	u16 *red, *green, *blue, *transp;
  	u_int hred, hgreen, hblue, htransp = 0xffff;
  
  	red = cmap->red;
  	green = cmap->green;
  	blue = cmap->blue;
  	transp = cmap->transp;
  	start = cmap->start;
714943766   Benjamin Herrenschmidt   [PATCH] fbdev: Ba...
228
229
  	if (start < 0 || (!info->fbops->fb_setcolreg &&
  			  !info->fbops->fb_setcmap))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  		return -EINVAL;
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  	if (info->fbops->fb_setcmap) {
  		rc = info->fbops->fb_setcmap(cmap, info);
  	} else {
  		for (i = 0; i < cmap->len; i++) {
  			hred = *red++;
  			hgreen = *green++;
  			hblue = *blue++;
  			if (transp)
  				htransp = *transp++;
  			if (info->fbops->fb_setcolreg(start++,
  						      hred, hgreen, hblue,
  						      htransp, info))
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	}
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
246
247
248
249
  	if (rc == 0)
  		fb_copy_cmap(cmap, &info->cmap);
  
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
  }
  
  int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
  {
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
254
255
  	int rc, size = cmap->len * sizeof(u16);
  	struct fb_cmap umap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

1e7c78048   Dan Carpenter   fbcmap: integer o...
257
258
  	if (size < 0 || size < cmap->len)
  		return -E2BIG;
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
259
  	memset(&umap, 0, sizeof(struct fb_cmap));
1e7c78048   Dan Carpenter   fbcmap: integer o...
260
261
  	rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
  				GFP_KERNEL);
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
262
  	if (rc)
714943766   Benjamin Herrenschmidt   [PATCH] fbdev: Ba...
263
  		return rc;
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
264
265
266
267
  	if (copy_from_user(umap.red, cmap->red, size) ||
  	    copy_from_user(umap.green, cmap->green, size) ||
  	    copy_from_user(umap.blue, cmap->blue, size) ||
  	    (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) {
1f5e31d7e   Andrea Righi   fbmem: don't call...
268
269
  		rc = -EFAULT;
  		goto out;
714943766   Benjamin Herrenschmidt   [PATCH] fbdev: Ba...
270
  	}
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
271
  	umap.start = cmap->start;
1f5e31d7e   Andrea Righi   fbmem: don't call...
272
273
274
275
276
277
278
279
280
  	if (!lock_fb_info(info)) {
  		rc = -ENODEV;
  		goto out;
  	}
  	if (cmap->start < 0 || (!info->fbops->fb_setcolreg &&
  				!info->fbops->fb_setcmap)) {
  		rc = -EINVAL;
  		goto out1;
  	}
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
281
  	rc = fb_set_cmap(&umap, info);
1f5e31d7e   Andrea Righi   fbmem: don't call...
282
283
284
  out1:
  	unlock_fb_info(info);
  out:
03e259a9c   Michal Januszewski   [PATCH] fbdev: up...
285
286
  	fb_dealloc_cmap(&umap);
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
295
296
297
298
  }
  
  /**
   *	fb_default_cmap - get default colormap
   *	@len: size of palette for a depth
   *
   *	Gets the default colormap for a specific screen depth.  @len
   *	is the size of the palette for a particular screen depth.
   *
   *	Returns pointer to a frame buffer colormap structure.
   *
   */
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
299
  const struct fb_cmap *fb_default_cmap(int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  {
      if (len <= 2)
  	return &default_2_colors;
      if (len <= 4)
  	return &default_4_colors;
      if (len <= 8)
  	return &default_8_colors;
      return &default_16_colors;
  }
  
  
  /**
   *	fb_invert_cmaps - invert all defaults colormaps
   *
   *	Invert all default colormaps.
   *
   */
  
  void fb_invert_cmaps(void)
  {
      u_int i;
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
321
      for (i = 0; i < ARRAY_SIZE(red2); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
  	red2[i] = ~red2[i];
  	green2[i] = ~green2[i];
  	blue2[i] = ~blue2[i];
      }
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
326
      for (i = 0; i < ARRAY_SIZE(red4); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
  	red4[i] = ~red4[i];
  	green4[i] = ~green4[i];
  	blue4[i] = ~blue4[i];
      }
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
331
      for (i = 0; i < ARRAY_SIZE(red8); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
  	red8[i] = ~red8[i];
  	green8[i] = ~green8[i];
  	blue8[i] = ~blue8[i];
      }
adf6b2065   Helge Deller   [PATCH] fbcmap.c:...
336
      for (i = 0; i < ARRAY_SIZE(red16); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  	red16[i] = ~red16[i];
  	green16[i] = ~green16[i];
  	blue16[i] = ~blue16[i];
      }
  }
  
  
      /*
       *  Visible symbols for modules
       */
  
  EXPORT_SYMBOL(fb_alloc_cmap);
  EXPORT_SYMBOL(fb_dealloc_cmap);
  EXPORT_SYMBOL(fb_copy_cmap);
  EXPORT_SYMBOL(fb_set_cmap);
  EXPORT_SYMBOL(fb_default_cmap);
  EXPORT_SYMBOL(fb_invert_cmaps);