Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fbmem.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/fbmem.c
3  *
4  * Copyright (C) 1994 Martin Schaller
5  *
6  * 2001 - Documented with DocBook
7  * - Brad Douglas <[email protected]>
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
11  * for more details.
12  */
13 
14 #include <linux/module.h>
15 
16 #include <linux/compat.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/kernel.h>
20 #include <linux/major.h>
21 #include <linux/slab.h>
22 #include <linux/mm.h>
23 #include <linux/mman.h>
24 #include <linux/vt.h>
25 #include <linux/init.h>
26 #include <linux/linux_logo.h>
27 #include <linux/proc_fs.h>
28 #include <linux/seq_file.h>
29 #include <linux/console.h>
30 #include <linux/kmod.h>
31 #include <linux/err.h>
32 #include <linux/device.h>
33 #include <linux/efi.h>
34 #include <linux/fb.h>
35 
36 #include <asm/fb.h>
37 
38 
39  /*
40  * Frame buffer device initialization and setup routines
41  */
42 
43 #define FBPIXMAPSIZE (1024 * 8)
44 
45 static DEFINE_MUTEX(registration_lock);
48 
49 static struct fb_info *get_fb_info(unsigned int idx)
50 {
51  struct fb_info *fb_info;
52 
53  if (idx >= FB_MAX)
54  return ERR_PTR(-ENODEV);
55 
56  mutex_lock(&registration_lock);
57  fb_info = registered_fb[idx];
58  if (fb_info)
59  atomic_inc(&fb_info->count);
60  mutex_unlock(&registration_lock);
61 
62  return fb_info;
63 }
64 
65 static void put_fb_info(struct fb_info *fb_info)
66 {
67  if (!atomic_dec_and_test(&fb_info->count))
68  return;
69  if (fb_info->fbops->fb_destroy)
70  fb_info->fbops->fb_destroy(fb_info);
71 }
72 
73 int lock_fb_info(struct fb_info *info)
74 {
75  mutex_lock(&info->lock);
76  if (!info->fbops) {
77  mutex_unlock(&info->lock);
78  return 0;
79  }
80  return 1;
81 }
83 
84 /*
85  * Helpers
86  */
87 
89  struct fb_fix_screeninfo *fix)
90 {
91  int depth = 0;
92 
93  if (fix->visual == FB_VISUAL_MONO01 ||
94  fix->visual == FB_VISUAL_MONO10)
95  depth = 1;
96  else {
97  if (var->green.length == var->blue.length &&
98  var->green.length == var->red.length &&
99  var->green.offset == var->blue.offset &&
100  var->green.offset == var->red.offset)
101  depth = var->green.length;
102  else
103  depth = var->green.length + var->red.length +
104  var->blue.length;
105  }
106 
107  return depth;
108 }
110 
111 /*
112  * Data padding functions.
113  */
114 void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
115 {
116  __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
117 }
119 
121  u32 shift_high, u32 shift_low, u32 mod)
122 {
123  u8 mask = (u8) (0xfff << shift_high), tmp;
124  int i, j;
125 
126  for (i = height; i--; ) {
127  for (j = 0; j < idx; j++) {
128  tmp = dst[j];
129  tmp &= mask;
130  tmp |= *src >> shift_low;
131  dst[j] = tmp;
132  tmp = *src << shift_high;
133  dst[j+1] = tmp;
134  src++;
135  }
136  tmp = dst[idx];
137  tmp &= mask;
138  tmp |= *src >> shift_low;
139  dst[idx] = tmp;
140  if (shift_high < mod) {
141  tmp = *src << shift_high;
142  dst[idx+1] = tmp;
143  }
144  src++;
145  dst += d_pitch;
146  }
147 }
149 
150 /*
151  * we need to lock this section since fb_cursor
152  * may use fb_imageblit()
153  */
154 char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
155 {
156  u32 align = buf->buf_align - 1, offset;
157  char *addr = buf->addr;
158 
159  /* If IO mapped, we need to sync before access, no sharing of
160  * the pixmap is done
161  */
162  if (buf->flags & FB_PIXMAP_IO) {
163  if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
164  info->fbops->fb_sync(info);
165  return addr;
166  }
167 
168  /* See if we fit in the remaining pixmap space */
169  offset = buf->offset + align;
170  offset &= ~align;
171  if (offset + size > buf->size) {
172  /* We do not fit. In order to be able to re-use the buffer,
173  * we must ensure no asynchronous DMA'ing or whatever operation
174  * is in progress, we sync for that.
175  */
176  if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
177  info->fbops->fb_sync(info);
178  offset = 0;
179  }
180  buf->offset = offset + size;
181  addr += offset;
182 
183  return addr;
184 }
185 
186 #ifdef CONFIG_LOGO
187 
188 static inline unsigned safe_shift(unsigned d, int n)
189 {
190  return n < 0 ? d >> -n : d << n;
191 }
192 
193 static void fb_set_logocmap(struct fb_info *info,
194  const struct linux_logo *logo)
195 {
196  struct fb_cmap palette_cmap;
197  u16 palette_green[16];
198  u16 palette_blue[16];
199  u16 palette_red[16];
200  int i, j, n;
201  const unsigned char *clut = logo->clut;
202 
203  palette_cmap.start = 0;
204  palette_cmap.len = 16;
205  palette_cmap.red = palette_red;
206  palette_cmap.green = palette_green;
207  palette_cmap.blue = palette_blue;
208  palette_cmap.transp = NULL;
209 
210  for (i = 0; i < logo->clutsize; i += n) {
211  n = logo->clutsize - i;
212  /* palette_cmap provides space for only 16 colors at once */
213  if (n > 16)
214  n = 16;
215  palette_cmap.start = 32 + i;
216  palette_cmap.len = n;
217  for (j = 0; j < n; ++j) {
218  palette_cmap.red[j] = clut[0] << 8 | clut[0];
219  palette_cmap.green[j] = clut[1] << 8 | clut[1];
220  palette_cmap.blue[j] = clut[2] << 8 | clut[2];
221  clut += 3;
222  }
223  fb_set_cmap(&palette_cmap, info);
224  }
225 }
226 
227 static void fb_set_logo_truepalette(struct fb_info *info,
228  const struct linux_logo *logo,
229  u32 *palette)
230 {
231  static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
232  unsigned char redmask, greenmask, bluemask;
233  int redshift, greenshift, blueshift;
234  int i;
235  const unsigned char *clut = logo->clut;
236 
237  /*
238  * We have to create a temporary palette since console palette is only
239  * 16 colors long.
240  */
241  /* Bug: Doesn't obey msb_right ... (who needs that?) */
242  redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8];
243  greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
244  bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8];
245  redshift = info->var.red.offset - (8 - info->var.red.length);
246  greenshift = info->var.green.offset - (8 - info->var.green.length);
247  blueshift = info->var.blue.offset - (8 - info->var.blue.length);
248 
249  for ( i = 0; i < logo->clutsize; i++) {
250  palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
251  safe_shift((clut[1] & greenmask), greenshift) |
252  safe_shift((clut[2] & bluemask), blueshift));
253  clut += 3;
254  }
255 }
256 
257 static void fb_set_logo_directpalette(struct fb_info *info,
258  const struct linux_logo *logo,
259  u32 *palette)
260 {
261  int redshift, greenshift, blueshift;
262  int i;
263 
264  redshift = info->var.red.offset;
265  greenshift = info->var.green.offset;
266  blueshift = info->var.blue.offset;
267 
268  for (i = 32; i < 32 + logo->clutsize; i++)
269  palette[i] = i << redshift | i << greenshift | i << blueshift;
270 }
271 
272 static void fb_set_logo(struct fb_info *info,
273  const struct linux_logo *logo, u8 *dst,
274  int depth)
275 {
276  int i, j, k;
277  const u8 *src = logo->data;
278  u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
279  u8 fg = 1, d;
280 
281  switch (fb_get_color_depth(&info->var, &info->fix)) {
282  case 1:
283  fg = 1;
284  break;
285  case 2:
286  fg = 3;
287  break;
288  default:
289  fg = 7;
290  break;
291  }
292 
293  if (info->fix.visual == FB_VISUAL_MONO01 ||
294  info->fix.visual == FB_VISUAL_MONO10)
295  fg = ~((u8) (0xfff << info->var.green.length));
296 
297  switch (depth) {
298  case 4:
299  for (i = 0; i < logo->height; i++)
300  for (j = 0; j < logo->width; src++) {
301  *dst++ = *src >> 4;
302  j++;
303  if (j < logo->width) {
304  *dst++ = *src & 0x0f;
305  j++;
306  }
307  }
308  break;
309  case 1:
310  for (i = 0; i < logo->height; i++) {
311  for (j = 0; j < logo->width; src++) {
312  d = *src ^ xor;
313  for (k = 7; k >= 0; k--) {
314  *dst++ = ((d >> k) & 1) ? fg : 0;
315  j++;
316  }
317  }
318  }
319  break;
320  }
321 }
322 
323 /*
324  * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors),
325  * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on
326  * the visual format and color depth of the framebuffer, the DAC, the
327  * pseudo_palette, and the logo data will be adjusted accordingly.
328  *
329  * Case 1 - linux_logo_clut224:
330  * Color exceeds the number of console colors (16), thus we set the hardware DAC
331  * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set.
332  *
333  * For visuals that require color info from the pseudo_palette, we also construct
334  * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
335  * will be set.
336  *
337  * Case 2 - linux_logo_vga16:
338  * The number of colors just matches the console colors, thus there is no need
339  * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie,
340  * each byte contains color information for two pixels (upper and lower nibble).
341  * To be consistent with fb_imageblit() usage, we therefore separate the two
342  * nibbles into separate bytes. The "depth" flag will be set to 4.
343  *
344  * Case 3 - linux_logo_mono:
345  * This is similar with Case 2. Each byte contains information for 8 pixels.
346  * We isolate each bit and expand each into a byte. The "depth" flag will
347  * be set to 1.
348  */
349 static struct logo_data {
350  int depth;
351  int needs_directpalette;
352  int needs_truepalette;
353  int needs_cmapreset;
354  const struct linux_logo *logo;
355 } fb_logo __read_mostly;
356 
357 static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
358 {
359  u32 size = width * height, i;
360 
361  out += size - 1;
362 
363  for (i = size; i--; )
364  *out-- = *in++;
365 }
366 
367 static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
368 {
369  int i, j, h = height - 1;
370 
371  for (i = 0; i < height; i++)
372  for (j = 0; j < width; j++)
373  out[height * j + h - i] = *in++;
374 }
375 
376 static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
377 {
378  int i, j, w = width - 1;
379 
380  for (i = 0; i < height; i++)
381  for (j = 0; j < width; j++)
382  out[height * (w - j) + i] = *in++;
383 }
384 
385 static void fb_rotate_logo(struct fb_info *info, u8 *dst,
386  struct fb_image *image, int rotate)
387 {
388  u32 tmp;
389 
390  if (rotate == FB_ROTATE_UD) {
391  fb_rotate_logo_ud(image->data, dst, image->width,
392  image->height);
393  image->dx = info->var.xres - image->width - image->dx;
394  image->dy = info->var.yres - image->height - image->dy;
395  } else if (rotate == FB_ROTATE_CW) {
396  fb_rotate_logo_cw(image->data, dst, image->width,
397  image->height);
398  tmp = image->width;
399  image->width = image->height;
400  image->height = tmp;
401  tmp = image->dy;
402  image->dy = image->dx;
403  image->dx = info->var.xres - image->width - tmp;
404  } else if (rotate == FB_ROTATE_CCW) {
405  fb_rotate_logo_ccw(image->data, dst, image->width,
406  image->height);
407  tmp = image->width;
408  image->width = image->height;
409  image->height = tmp;
410  tmp = image->dx;
411  image->dx = image->dy;
412  image->dy = info->var.yres - image->height - tmp;
413  }
414 
415  image->data = dst;
416 }
417 
418 static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
419  int rotate, unsigned int num)
420 {
421  unsigned int x;
422 
423  if (rotate == FB_ROTATE_UR) {
424  for (x = 0;
425  x < num && image->dx + image->width <= info->var.xres;
426  x++) {
427  info->fbops->fb_imageblit(info, image);
428  image->dx += image->width + 8;
429  }
430  } else if (rotate == FB_ROTATE_UD) {
431  for (x = 0; x < num && image->dx >= 0; x++) {
432  info->fbops->fb_imageblit(info, image);
433  image->dx -= image->width + 8;
434  }
435  } else if (rotate == FB_ROTATE_CW) {
436  for (x = 0;
437  x < num && image->dy + image->height <= info->var.yres;
438  x++) {
439  info->fbops->fb_imageblit(info, image);
440  image->dy += image->height + 8;
441  }
442  } else if (rotate == FB_ROTATE_CCW) {
443  for (x = 0; x < num && image->dy >= 0; x++) {
444  info->fbops->fb_imageblit(info, image);
445  image->dy -= image->height + 8;
446  }
447  }
448 }
449 
450 static int fb_show_logo_line(struct fb_info *info, int rotate,
451  const struct linux_logo *logo, int y,
452  unsigned int n)
453 {
454  u32 *palette = NULL, *saved_pseudo_palette = NULL;
455  unsigned char *logo_new = NULL, *logo_rotate = NULL;
456  struct fb_image image;
457 
458  /* Return if the frame buffer is not mapped or suspended */
459  if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
460  info->flags & FBINFO_MODULE)
461  return 0;
462 
463  image.depth = 8;
464  image.data = logo->data;
465 
466  if (fb_logo.needs_cmapreset)
467  fb_set_logocmap(info, logo);
468 
469  if (fb_logo.needs_truepalette ||
470  fb_logo.needs_directpalette) {
471  palette = kmalloc(256 * 4, GFP_KERNEL);
472  if (palette == NULL)
473  return 0;
474 
475  if (fb_logo.needs_truepalette)
476  fb_set_logo_truepalette(info, logo, palette);
477  else
478  fb_set_logo_directpalette(info, logo, palette);
479 
480  saved_pseudo_palette = info->pseudo_palette;
481  info->pseudo_palette = palette;
482  }
483 
484  if (fb_logo.depth <= 4) {
485  logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
486  if (logo_new == NULL) {
487  kfree(palette);
488  if (saved_pseudo_palette)
489  info->pseudo_palette = saved_pseudo_palette;
490  return 0;
491  }
492  image.data = logo_new;
493  fb_set_logo(info, logo, logo_new, fb_logo.depth);
494  }
495 
496  image.dx = 0;
497  image.dy = y;
498  image.width = logo->width;
499  image.height = logo->height;
500 
501  if (rotate) {
502  logo_rotate = kmalloc(logo->width *
503  logo->height, GFP_KERNEL);
504  if (logo_rotate)
505  fb_rotate_logo(info, logo_rotate, &image, rotate);
506  }
507 
508  fb_do_show_logo(info, &image, rotate, n);
509 
510  kfree(palette);
511  if (saved_pseudo_palette != NULL)
512  info->pseudo_palette = saved_pseudo_palette;
513  kfree(logo_new);
514  kfree(logo_rotate);
515  return logo->height;
516 }
517 
518 
519 #ifdef CONFIG_FB_LOGO_EXTRA
520 
521 #define FB_LOGO_EX_NUM_MAX 10
522 static struct logo_data_extra {
523  const struct linux_logo *logo;
524  unsigned int n;
525 } fb_logo_ex[FB_LOGO_EX_NUM_MAX];
526 static unsigned int fb_logo_ex_num;
527 
528 void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
529 {
530  if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
531  return;
532 
533  fb_logo_ex[fb_logo_ex_num].logo = logo;
534  fb_logo_ex[fb_logo_ex_num].n = n;
535  fb_logo_ex_num++;
536 }
537 
538 static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
539  unsigned int yres)
540 {
541  unsigned int i;
542 
543  /* FIXME: logo_ex supports only truecolor fb. */
544  if (info->fix.visual != FB_VISUAL_TRUECOLOR)
545  fb_logo_ex_num = 0;
546 
547  for (i = 0; i < fb_logo_ex_num; i++) {
548  if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
549  fb_logo_ex[i].logo = NULL;
550  continue;
551  }
552  height += fb_logo_ex[i].logo->height;
553  if (height > yres) {
554  height -= fb_logo_ex[i].logo->height;
555  fb_logo_ex_num = i;
556  break;
557  }
558  }
559  return height;
560 }
561 
562 static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
563 {
564  unsigned int i;
565 
566  for (i = 0; i < fb_logo_ex_num; i++)
567  y += fb_show_logo_line(info, rotate,
568  fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
569 
570  return y;
571 }
572 
573 #else /* !CONFIG_FB_LOGO_EXTRA */
574 
575 static inline int fb_prepare_extra_logos(struct fb_info *info,
576  unsigned int height,
577  unsigned int yres)
578 {
579  return height;
580 }
581 
582 static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
583 {
584  return y;
585 }
586 
587 #endif /* CONFIG_FB_LOGO_EXTRA */
588 
589 
590 int fb_prepare_logo(struct fb_info *info, int rotate)
591 {
592  int depth = fb_get_color_depth(&info->var, &info->fix);
593  unsigned int yres;
594 
595  memset(&fb_logo, 0, sizeof(struct logo_data));
596 
597  if (info->flags & FBINFO_MISC_TILEBLITTING ||
598  info->flags & FBINFO_MODULE)
599  return 0;
600 
601  if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
602  depth = info->var.blue.length;
603  if (info->var.red.length < depth)
604  depth = info->var.red.length;
605  if (info->var.green.length < depth)
606  depth = info->var.green.length;
607  }
608 
609  if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
610  /* assume console colormap */
611  depth = 4;
612  }
613 
614  /* Return if no suitable logo was found */
615  fb_logo.logo = fb_find_logo(depth);
616 
617  if (!fb_logo.logo) {
618  return 0;
619  }
620 
621  if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
622  yres = info->var.yres;
623  else
624  yres = info->var.xres;
625 
626  if (fb_logo.logo->height > yres) {
627  fb_logo.logo = NULL;
628  return 0;
629  }
630 
631  /* What depth we asked for might be different from what we get */
632  if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
633  fb_logo.depth = 8;
634  else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
635  fb_logo.depth = 4;
636  else
637  fb_logo.depth = 1;
638 
639 
640  if (fb_logo.depth > 4 && depth > 4) {
641  switch (info->fix.visual) {
642  case FB_VISUAL_TRUECOLOR:
643  fb_logo.needs_truepalette = 1;
644  break;
646  fb_logo.needs_directpalette = 1;
647  fb_logo.needs_cmapreset = 1;
648  break;
650  fb_logo.needs_cmapreset = 1;
651  break;
652  }
653  }
654 
655  return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
656 }
657 
658 int fb_show_logo(struct fb_info *info, int rotate)
659 {
660  int y;
661 
662  y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
663  num_online_cpus());
664  y = fb_show_extra_logos(info, y, rotate);
665 
666  return y;
667 }
668 #else
669 int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
670 int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
671 #endif /* CONFIG_LOGO */
672 
673 static void *fb_seq_start(struct seq_file *m, loff_t *pos)
674 {
675  mutex_lock(&registration_lock);
676  return (*pos < FB_MAX) ? pos : NULL;
677 }
678 
679 static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
680 {
681  (*pos)++;
682  return (*pos < FB_MAX) ? pos : NULL;
683 }
684 
685 static void fb_seq_stop(struct seq_file *m, void *v)
686 {
687  mutex_unlock(&registration_lock);
688 }
689 
690 static int fb_seq_show(struct seq_file *m, void *v)
691 {
692  int i = *(loff_t *)v;
693  struct fb_info *fi = registered_fb[i];
694 
695  if (fi)
696  seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
697  return 0;
698 }
699 
700 static const struct seq_operations proc_fb_seq_ops = {
701  .start = fb_seq_start,
702  .next = fb_seq_next,
703  .stop = fb_seq_stop,
704  .show = fb_seq_show,
705 };
706 
707 static int proc_fb_open(struct inode *inode, struct file *file)
708 {
709  return seq_open(file, &proc_fb_seq_ops);
710 }
711 
712 static const struct file_operations fb_proc_fops = {
713  .owner = THIS_MODULE,
714  .open = proc_fb_open,
715  .read = seq_read,
716  .llseek = seq_lseek,
717  .release = seq_release,
718 };
719 
720 /*
721  * We hold a reference to the fb_info in file->private_data,
722  * but if the current registered fb has changed, we don't
723  * actually want to use it.
724  *
725  * So look up the fb_info using the inode minor number,
726  * and just verify it against the reference we have.
727  */
728 static struct fb_info *file_fb_info(struct file *file)
729 {
730  struct inode *inode = file->f_path.dentry->d_inode;
731  int fbidx = iminor(inode);
732  struct fb_info *info = registered_fb[fbidx];
733 
734  if (info != file->private_data)
735  info = NULL;
736  return info;
737 }
738 
739 static ssize_t
740 fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
741 {
742  unsigned long p = *ppos;
743  struct fb_info *info = file_fb_info(file);
744  u8 *buffer, *dst;
745  u8 __iomem *src;
746  int c, cnt = 0, err = 0;
747  unsigned long total_size;
748 
749  if (!info || ! info->screen_base)
750  return -ENODEV;
751 
752  if (info->state != FBINFO_STATE_RUNNING)
753  return -EPERM;
754 
755  if (info->fbops->fb_read)
756  return info->fbops->fb_read(info, buf, count, ppos);
757 
758  total_size = info->screen_size;
759 
760  if (total_size == 0)
761  total_size = info->fix.smem_len;
762 
763  if (p >= total_size)
764  return 0;
765 
766  if (count >= total_size)
767  count = total_size;
768 
769  if (count + p > total_size)
770  count = total_size - p;
771 
772  buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
773  GFP_KERNEL);
774  if (!buffer)
775  return -ENOMEM;
776 
777  src = (u8 __iomem *) (info->screen_base + p);
778 
779  if (info->fbops->fb_sync)
780  info->fbops->fb_sync(info);
781 
782  while (count) {
783  c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
784  dst = buffer;
785  fb_memcpy_fromfb(dst, src, c);
786  dst += c;
787  src += c;
788 
789  if (copy_to_user(buf, buffer, c)) {
790  err = -EFAULT;
791  break;
792  }
793  *ppos += c;
794  buf += c;
795  cnt += c;
796  count -= c;
797  }
798 
799  kfree(buffer);
800 
801  return (err) ? err : cnt;
802 }
803 
804 static ssize_t
805 fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
806 {
807  unsigned long p = *ppos;
808  struct fb_info *info = file_fb_info(file);
809  u8 *buffer, *src;
810  u8 __iomem *dst;
811  int c, cnt = 0, err = 0;
812  unsigned long total_size;
813 
814  if (!info || !info->screen_base)
815  return -ENODEV;
816 
817  if (info->state != FBINFO_STATE_RUNNING)
818  return -EPERM;
819 
820  if (info->fbops->fb_write)
821  return info->fbops->fb_write(info, buf, count, ppos);
822 
823  total_size = info->screen_size;
824 
825  if (total_size == 0)
826  total_size = info->fix.smem_len;
827 
828  if (p > total_size)
829  return -EFBIG;
830 
831  if (count > total_size) {
832  err = -EFBIG;
833  count = total_size;
834  }
835 
836  if (count + p > total_size) {
837  if (!err)
838  err = -ENOSPC;
839 
840  count = total_size - p;
841  }
842 
843  buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
844  GFP_KERNEL);
845  if (!buffer)
846  return -ENOMEM;
847 
848  dst = (u8 __iomem *) (info->screen_base + p);
849 
850  if (info->fbops->fb_sync)
851  info->fbops->fb_sync(info);
852 
853  while (count) {
854  c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
855  src = buffer;
856 
857  if (copy_from_user(src, buf, c)) {
858  err = -EFAULT;
859  break;
860  }
861 
862  fb_memcpy_tofb(dst, src, c);
863  dst += c;
864  src += c;
865  *ppos += c;
866  buf += c;
867  cnt += c;
868  count -= c;
869  }
870 
871  kfree(buffer);
872 
873  return (cnt) ? cnt : err;
874 }
875 
876 int
877 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
878 {
879  struct fb_fix_screeninfo *fix = &info->fix;
880  unsigned int yres = info->var.yres;
881  int err = 0;
882 
883  if (var->yoffset > 0) {
884  if (var->vmode & FB_VMODE_YWRAP) {
885  if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
886  err = -EINVAL;
887  else
888  yres = 0;
889  } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
890  err = -EINVAL;
891  }
892 
893  if (var->xoffset > 0 && (!fix->xpanstep ||
894  (var->xoffset % fix->xpanstep)))
895  err = -EINVAL;
896 
897  if (err || !info->fbops->fb_pan_display ||
898  var->yoffset > info->var.yres_virtual - yres ||
899  var->xoffset > info->var.xres_virtual - info->var.xres)
900  return -EINVAL;
901 
902  if ((err = info->fbops->fb_pan_display(var, info)))
903  return err;
904  info->var.xoffset = var->xoffset;
905  info->var.yoffset = var->yoffset;
906  if (var->vmode & FB_VMODE_YWRAP)
907  info->var.vmode |= FB_VMODE_YWRAP;
908  else
909  info->var.vmode &= ~FB_VMODE_YWRAP;
910  return 0;
911 }
912 
913 static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
914  u32 activate)
915 {
916  struct fb_event event;
917  struct fb_blit_caps caps, fbcaps;
918  int err = 0;
919 
920  memset(&caps, 0, sizeof(caps));
921  memset(&fbcaps, 0, sizeof(fbcaps));
922  caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
923  event.info = info;
924  event.data = &caps;
926  info->fbops->fb_get_caps(info, &fbcaps, var);
927 
928  if (((fbcaps.x ^ caps.x) & caps.x) ||
929  ((fbcaps.y ^ caps.y) & caps.y) ||
930  (fbcaps.len < caps.len))
931  err = -EINVAL;
932 
933  return err;
934 }
935 
936 int
937 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
938 {
939  int flags = info->flags;
940  int ret = 0;
941 
942  if (var->activate & FB_ACTIVATE_INV_MODE) {
943  struct fb_videomode mode1, mode2;
944 
945  fb_var_to_videomode(&mode1, var);
946  fb_var_to_videomode(&mode2, &info->var);
947  /* make sure we don't delete the videomode of current var */
948  ret = fb_mode_is_equal(&mode1, &mode2);
949 
950  if (!ret) {
951  struct fb_event event;
952 
953  event.info = info;
954  event.data = &mode1;
956  }
957 
958  if (!ret)
959  fb_delete_videomode(&mode1, &info->modelist);
960 
961 
962  ret = (ret) ? -EINVAL : 0;
963  goto done;
964  }
965 
966  if ((var->activate & FB_ACTIVATE_FORCE) ||
967  memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
968  u32 activate = var->activate;
969 
970  /* When using FOURCC mode, make sure the red, green, blue and
971  * transp fields are set to 0.
972  */
973  if ((info->fix.capabilities & FB_CAP_FOURCC) &&
974  var->grayscale > 1) {
975  if (var->red.offset || var->green.offset ||
976  var->blue.offset || var->transp.offset ||
977  var->red.length || var->green.length ||
978  var->blue.length || var->transp.length ||
979  var->red.msb_right || var->green.msb_right ||
980  var->blue.msb_right || var->transp.msb_right)
981  return -EINVAL;
982  }
983 
984  if (!info->fbops->fb_check_var) {
985  *var = info->var;
986  goto done;
987  }
988 
989  ret = info->fbops->fb_check_var(var, info);
990 
991  if (ret)
992  goto done;
993 
994  if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
995  struct fb_var_screeninfo old_var;
996  struct fb_videomode mode;
997 
998  if (info->fbops->fb_get_caps) {
999  ret = fb_check_caps(info, var, activate);
1000 
1001  if (ret)
1002  goto done;
1003  }
1004 
1005  old_var = info->var;
1006  info->var = *var;
1007 
1008  if (info->fbops->fb_set_par) {
1009  ret = info->fbops->fb_set_par(info);
1010 
1011  if (ret) {
1012  info->var = old_var;
1013  printk(KERN_WARNING "detected "
1014  "fb_set_par error, "
1015  "error code: %d\n", ret);
1016  goto done;
1017  }
1018  }
1019 
1020  fb_pan_display(info, &info->var);
1021  fb_set_cmap(&info->cmap, info);
1022  fb_var_to_videomode(&mode, &info->var);
1023 
1024  if (info->modelist.prev && info->modelist.next &&
1025  !list_empty(&info->modelist))
1026  ret = fb_add_videomode(&mode, &info->modelist);
1027 
1028  if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
1029  struct fb_event event;
1030  int evnt = (activate & FB_ACTIVATE_ALL) ?
1033 
1034  info->flags &= ~FBINFO_MISC_USEREVENT;
1035  event.info = info;
1036  event.data = &mode;
1037  fb_notifier_call_chain(evnt, &event);
1038  }
1039  }
1040  }
1041 
1042  done:
1043  return ret;
1044 }
1045 
1046 int
1047 fb_blank(struct fb_info *info, int blank)
1048 {
1049  struct fb_event event;
1050  int ret = -EINVAL, early_ret;
1051 
1052  if (blank > FB_BLANK_POWERDOWN)
1053  blank = FB_BLANK_POWERDOWN;
1054 
1055  event.info = info;
1056  event.data = &blank;
1057 
1058  early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
1059 
1060  if (info->fbops->fb_blank)
1061  ret = info->fbops->fb_blank(blank, info);
1062 
1063  if (!ret)
1065  else {
1066  /*
1067  * if fb_blank is failed then revert effects of
1068  * the early blank event.
1069  */
1070  if (!early_ret)
1072  }
1073 
1074  return ret;
1075 }
1076 
1077 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1078  unsigned long arg)
1079 {
1080  struct fb_ops *fb;
1081  struct fb_var_screeninfo var;
1082  struct fb_fix_screeninfo fix;
1083  struct fb_con2fbmap con2fb;
1084  struct fb_cmap cmap_from;
1085  struct fb_cmap_user cmap;
1086  struct fb_event event;
1087  void __user *argp = (void __user *)arg;
1088  long ret = 0;
1089 
1090  switch (cmd) {
1091  case FBIOGET_VSCREENINFO:
1092  if (!lock_fb_info(info))
1093  return -ENODEV;
1094  var = info->var;
1095  unlock_fb_info(info);
1096 
1097  ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
1098  break;
1099  case FBIOPUT_VSCREENINFO:
1100  if (copy_from_user(&var, argp, sizeof(var)))
1101  return -EFAULT;
1102  if (!lock_fb_info(info))
1103  return -ENODEV;
1104  console_lock();
1105  info->flags |= FBINFO_MISC_USEREVENT;
1106  ret = fb_set_var(info, &var);
1107  info->flags &= ~FBINFO_MISC_USEREVENT;
1108  console_unlock();
1109  unlock_fb_info(info);
1110  if (!ret && copy_to_user(argp, &var, sizeof(var)))
1111  ret = -EFAULT;
1112  break;
1113  case FBIOGET_FSCREENINFO:
1114  if (!lock_fb_info(info))
1115  return -ENODEV;
1116  fix = info->fix;
1117  unlock_fb_info(info);
1118 
1119  ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
1120  break;
1121  case FBIOPUTCMAP:
1122  if (copy_from_user(&cmap, argp, sizeof(cmap)))
1123  return -EFAULT;
1124  ret = fb_set_user_cmap(&cmap, info);
1125  break;
1126  case FBIOGETCMAP:
1127  if (copy_from_user(&cmap, argp, sizeof(cmap)))
1128  return -EFAULT;
1129  if (!lock_fb_info(info))
1130  return -ENODEV;
1131  cmap_from = info->cmap;
1132  unlock_fb_info(info);
1133  ret = fb_cmap_to_user(&cmap_from, &cmap);
1134  break;
1135  case FBIOPAN_DISPLAY:
1136  if (copy_from_user(&var, argp, sizeof(var)))
1137  return -EFAULT;
1138  if (!lock_fb_info(info))
1139  return -ENODEV;
1140  console_lock();
1141  ret = fb_pan_display(info, &var);
1142  console_unlock();
1143  unlock_fb_info(info);
1144  if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1145  return -EFAULT;
1146  break;
1147  case FBIO_CURSOR:
1148  ret = -EINVAL;
1149  break;
1150  case FBIOGET_CON2FBMAP:
1151  if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1152  return -EFAULT;
1153  if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1154  return -EINVAL;
1155  con2fb.framebuffer = -1;
1156  event.data = &con2fb;
1157  if (!lock_fb_info(info))
1158  return -ENODEV;
1159  event.info = info;
1161  unlock_fb_info(info);
1162  ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
1163  break;
1164  case FBIOPUT_CON2FBMAP:
1165  if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1166  return -EFAULT;
1167  if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1168  return -EINVAL;
1169  if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
1170  return -EINVAL;
1171  if (!registered_fb[con2fb.framebuffer])
1172  request_module("fb%d", con2fb.framebuffer);
1173  if (!registered_fb[con2fb.framebuffer]) {
1174  ret = -EINVAL;
1175  break;
1176  }
1177  event.data = &con2fb;
1178  if (!lock_fb_info(info))
1179  return -ENODEV;
1180  event.info = info;
1182  unlock_fb_info(info);
1183  break;
1184  case FBIOBLANK:
1185  if (!lock_fb_info(info))
1186  return -ENODEV;
1187  console_lock();
1188  info->flags |= FBINFO_MISC_USEREVENT;
1189  ret = fb_blank(info, arg);
1190  info->flags &= ~FBINFO_MISC_USEREVENT;
1191  console_unlock();
1192  unlock_fb_info(info);
1193  break;
1194  default:
1195  if (!lock_fb_info(info))
1196  return -ENODEV;
1197  fb = info->fbops;
1198  if (fb->fb_ioctl)
1199  ret = fb->fb_ioctl(info, cmd, arg);
1200  else
1201  ret = -ENOTTY;
1202  unlock_fb_info(info);
1203  }
1204  return ret;
1205 }
1206 
1207 static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1208 {
1209  struct fb_info *info = file_fb_info(file);
1210 
1211  if (!info)
1212  return -ENODEV;
1213  return do_fb_ioctl(info, cmd, arg);
1214 }
1215 
1216 #ifdef CONFIG_COMPAT
1217 struct fb_fix_screeninfo32 {
1218  char id[16];
1219  compat_caddr_t smem_start;
1220  u32 smem_len;
1221  u32 type;
1222  u32 type_aux;
1223  u32 visual;
1224  u16 xpanstep;
1225  u16 ypanstep;
1226  u16 ywrapstep;
1227  u32 line_length;
1228  compat_caddr_t mmio_start;
1229  u32 mmio_len;
1230  u32 accel;
1231  u16 reserved[3];
1232 };
1233 
1234 struct fb_cmap32 {
1235  u32 start;
1236  u32 len;
1241 };
1242 
1243 static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
1244  unsigned long arg)
1245 {
1246  struct fb_cmap_user __user *cmap;
1247  struct fb_cmap32 __user *cmap32;
1248  __u32 data;
1249  int err;
1250 
1251  cmap = compat_alloc_user_space(sizeof(*cmap));
1252  cmap32 = compat_ptr(arg);
1253 
1254  if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
1255  return -EFAULT;
1256 
1257  if (get_user(data, &cmap32->red) ||
1258  put_user(compat_ptr(data), &cmap->red) ||
1259  get_user(data, &cmap32->green) ||
1260  put_user(compat_ptr(data), &cmap->green) ||
1261  get_user(data, &cmap32->blue) ||
1262  put_user(compat_ptr(data), &cmap->blue) ||
1263  get_user(data, &cmap32->transp) ||
1264  put_user(compat_ptr(data), &cmap->transp))
1265  return -EFAULT;
1266 
1267  err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
1268 
1269  if (!err) {
1270  if (copy_in_user(&cmap32->start,
1271  &cmap->start,
1272  2 * sizeof(__u32)))
1273  err = -EFAULT;
1274  }
1275  return err;
1276 }
1277 
1278 static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
1279  struct fb_fix_screeninfo32 __user *fix32)
1280 {
1281  __u32 data;
1282  int err;
1283 
1284  err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
1285 
1286  data = (__u32) (unsigned long) fix->smem_start;
1287  err |= put_user(data, &fix32->smem_start);
1288 
1289  err |= put_user(fix->smem_len, &fix32->smem_len);
1290  err |= put_user(fix->type, &fix32->type);
1291  err |= put_user(fix->type_aux, &fix32->type_aux);
1292  err |= put_user(fix->visual, &fix32->visual);
1293  err |= put_user(fix->xpanstep, &fix32->xpanstep);
1294  err |= put_user(fix->ypanstep, &fix32->ypanstep);
1295  err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
1296  err |= put_user(fix->line_length, &fix32->line_length);
1297 
1298  data = (__u32) (unsigned long) fix->mmio_start;
1299  err |= put_user(data, &fix32->mmio_start);
1300 
1301  err |= put_user(fix->mmio_len, &fix32->mmio_len);
1302  err |= put_user(fix->accel, &fix32->accel);
1303  err |= copy_to_user(fix32->reserved, fix->reserved,
1304  sizeof(fix->reserved));
1305 
1306  return err;
1307 }
1308 
1309 static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
1310  unsigned long arg)
1311 {
1312  mm_segment_t old_fs;
1313  struct fb_fix_screeninfo fix;
1314  struct fb_fix_screeninfo32 __user *fix32;
1315  int err;
1316 
1317  fix32 = compat_ptr(arg);
1318 
1319  old_fs = get_fs();
1320  set_fs(KERNEL_DS);
1321  err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
1322  set_fs(old_fs);
1323 
1324  if (!err)
1325  err = do_fscreeninfo_to_user(&fix, fix32);
1326 
1327  return err;
1328 }
1329 
1330 static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1331  unsigned long arg)
1332 {
1333  struct fb_info *info = file_fb_info(file);
1334  struct fb_ops *fb;
1335  long ret = -ENOIOCTLCMD;
1336 
1337  if (!info)
1338  return -ENODEV;
1339  fb = info->fbops;
1340  switch(cmd) {
1341  case FBIOGET_VSCREENINFO:
1342  case FBIOPUT_VSCREENINFO:
1343  case FBIOPAN_DISPLAY:
1344  case FBIOGET_CON2FBMAP:
1345  case FBIOPUT_CON2FBMAP:
1346  arg = (unsigned long) compat_ptr(arg);
1347  case FBIOBLANK:
1348  ret = do_fb_ioctl(info, cmd, arg);
1349  break;
1350 
1351  case FBIOGET_FSCREENINFO:
1352  ret = fb_get_fscreeninfo(info, cmd, arg);
1353  break;
1354 
1355  case FBIOGETCMAP:
1356  case FBIOPUTCMAP:
1357  ret = fb_getput_cmap(info, cmd, arg);
1358  break;
1359 
1360  default:
1361  if (fb->fb_compat_ioctl)
1362  ret = fb->fb_compat_ioctl(info, cmd, arg);
1363  break;
1364  }
1365  return ret;
1366 }
1367 #endif
1368 
1369 static int
1370 fb_mmap(struct file *file, struct vm_area_struct * vma)
1371 {
1372  struct fb_info *info = file_fb_info(file);
1373  struct fb_ops *fb;
1374  unsigned long off;
1375  unsigned long start;
1376  u32 len;
1377 
1378  if (!info)
1379  return -ENODEV;
1380  if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1381  return -EINVAL;
1382  off = vma->vm_pgoff << PAGE_SHIFT;
1383  fb = info->fbops;
1384  if (!fb)
1385  return -ENODEV;
1386  mutex_lock(&info->mm_lock);
1387  if (fb->fb_mmap) {
1388  int res;
1389  res = fb->fb_mmap(info, vma);
1390  mutex_unlock(&info->mm_lock);
1391  return res;
1392  }
1393 
1394  /* frame buffer memory */
1395  start = info->fix.smem_start;
1396  len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
1397  if (off >= len) {
1398  /* memory mapped io */
1399  off -= len;
1400  if (info->var.accel_flags) {
1401  mutex_unlock(&info->mm_lock);
1402  return -EINVAL;
1403  }
1404  start = info->fix.mmio_start;
1405  len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
1406  }
1407  mutex_unlock(&info->mm_lock);
1408  start &= PAGE_MASK;
1409  if ((vma->vm_end - vma->vm_start + off) > len)
1410  return -EINVAL;
1411  off += start;
1412  vma->vm_pgoff = off >> PAGE_SHIFT;
1413  /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/
1414  vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
1415  fb_pgprotect(file, vma, off);
1416  if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1417  vma->vm_end - vma->vm_start, vma->vm_page_prot))
1418  return -EAGAIN;
1419  return 0;
1420 }
1421 
1422 static int
1423 fb_open(struct inode *inode, struct file *file)
1424 __acquires(&info->lock)
1425 __releases(&info->lock)
1426 {
1427  int fbidx = iminor(inode);
1428  struct fb_info *info;
1429  int res = 0;
1430 
1431  info = get_fb_info(fbidx);
1432  if (!info) {
1433  request_module("fb%d", fbidx);
1434  info = get_fb_info(fbidx);
1435  if (!info)
1436  return -ENODEV;
1437  }
1438  if (IS_ERR(info))
1439  return PTR_ERR(info);
1440 
1441  mutex_lock(&info->lock);
1442  if (!try_module_get(info->fbops->owner)) {
1443  res = -ENODEV;
1444  goto out;
1445  }
1446  file->private_data = info;
1447  if (info->fbops->fb_open) {
1448  res = info->fbops->fb_open(info,1);
1449  if (res)
1450  module_put(info->fbops->owner);
1451  }
1452 #ifdef CONFIG_FB_DEFERRED_IO
1453  if (info->fbdefio)
1454  fb_deferred_io_open(info, inode, file);
1455 #endif
1456 out:
1457  mutex_unlock(&info->lock);
1458  if (res)
1459  put_fb_info(info);
1460  return res;
1461 }
1462 
1463 static int
1464 fb_release(struct inode *inode, struct file *file)
1465 __acquires(&info->lock)
1466 __releases(&info->lock)
1467 {
1468  struct fb_info * const info = file->private_data;
1469 
1470  mutex_lock(&info->lock);
1471  if (info->fbops->fb_release)
1472  info->fbops->fb_release(info,1);
1473  module_put(info->fbops->owner);
1474  mutex_unlock(&info->lock);
1475  put_fb_info(info);
1476  return 0;
1477 }
1478 
1479 static const struct file_operations fb_fops = {
1480  .owner = THIS_MODULE,
1481  .read = fb_read,
1482  .write = fb_write,
1483  .unlocked_ioctl = fb_ioctl,
1484 #ifdef CONFIG_COMPAT
1485  .compat_ioctl = fb_compat_ioctl,
1486 #endif
1487  .mmap = fb_mmap,
1488  .open = fb_open,
1489  .release = fb_release,
1490 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1491  .get_unmapped_area = get_fb_unmapped_area,
1492 #endif
1493 #ifdef CONFIG_FB_DEFERRED_IO
1494  .fsync = fb_deferred_io_fsync,
1495 #endif
1496  .llseek = default_llseek,
1497 };
1498 
1499 struct class *fb_class;
1500 EXPORT_SYMBOL(fb_class);
1501 
1502 static int fb_check_foreignness(struct fb_info *fi)
1503 {
1504  const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
1505 
1506  fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
1507 
1508 #ifdef __BIG_ENDIAN
1509  fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
1510 #else
1511  fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
1512 #endif /* __BIG_ENDIAN */
1513 
1514  if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
1515  pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
1516  "support this framebuffer\n", fi->fix.id);
1517  return -ENOSYS;
1518  } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
1519  pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
1520  "support this framebuffer\n", fi->fix.id);
1521  return -ENOSYS;
1522  }
1523 
1524  return 0;
1525 }
1526 
1527 static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
1528 {
1529  /* is the generic aperture base the same as the HW one */
1530  if (gen->base == hw->base)
1531  return true;
1532  /* is the generic aperture base inside the hw base->hw base+size */
1533  if (gen->base > hw->base && gen->base < hw->base + hw->size)
1534  return true;
1535  return false;
1536 }
1537 
1538 static bool fb_do_apertures_overlap(struct apertures_struct *gena,
1539  struct apertures_struct *hwa)
1540 {
1541  int i, j;
1542  if (!hwa || !gena)
1543  return false;
1544 
1545  for (i = 0; i < hwa->count; ++i) {
1546  struct aperture *h = &hwa->ranges[i];
1547  for (j = 0; j < gena->count; ++j) {
1548  struct aperture *g = &gena->ranges[j];
1549  printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
1550  (unsigned long long)g->base,
1551  (unsigned long long)g->size,
1552  (unsigned long long)h->base,
1553  (unsigned long long)h->size);
1554  if (apertures_overlap(g, h))
1555  return true;
1556  }
1557  }
1558 
1559  return false;
1560 }
1561 
1562 static int do_unregister_framebuffer(struct fb_info *fb_info);
1563 
1564 #define VGA_FB_PHYS 0xA0000
1565 static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
1566  const char *name, bool primary)
1567 {
1568  int i;
1569 
1570  /* check all firmware fbs and kick off if the base addr overlaps */
1571  for (i = 0 ; i < FB_MAX; i++) {
1572  struct apertures_struct *gen_aper;
1573  if (!registered_fb[i])
1574  continue;
1575 
1577  continue;
1578 
1579  gen_aper = registered_fb[i]->apertures;
1580  if (fb_do_apertures_overlap(gen_aper, a) ||
1581  (primary && gen_aper && gen_aper->count &&
1582  gen_aper->ranges[0].base == VGA_FB_PHYS)) {
1583 
1584  printk(KERN_INFO "fb: conflicting fb hw usage "
1585  "%s vs %s - removing generic driver\n",
1586  name, registered_fb[i]->fix.id);
1587  do_unregister_framebuffer(registered_fb[i]);
1588  }
1589  }
1590 }
1591 
1592 static int do_register_framebuffer(struct fb_info *fb_info)
1593 {
1594  int i;
1595  struct fb_event event;
1596  struct fb_videomode mode;
1597 
1598  if (fb_check_foreignness(fb_info))
1599  return -ENOSYS;
1600 
1601  do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
1602  fb_is_primary_device(fb_info));
1603 
1604  if (num_registered_fb == FB_MAX)
1605  return -ENXIO;
1606 
1608  for (i = 0 ; i < FB_MAX; i++)
1609  if (!registered_fb[i])
1610  break;
1611  fb_info->node = i;
1612  atomic_set(&fb_info->count, 1);
1613  mutex_init(&fb_info->lock);
1614  mutex_init(&fb_info->mm_lock);
1615 
1616  fb_info->dev = device_create(fb_class, fb_info->device,
1617  MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
1618  if (IS_ERR(fb_info->dev)) {
1619  /* Not fatal */
1620  printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
1621  fb_info->dev = NULL;
1622  } else
1623  fb_init_device(fb_info);
1624 
1625  if (fb_info->pixmap.addr == NULL) {
1626  fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1627  if (fb_info->pixmap.addr) {
1628  fb_info->pixmap.size = FBPIXMAPSIZE;
1629  fb_info->pixmap.buf_align = 1;
1630  fb_info->pixmap.scan_align = 1;
1631  fb_info->pixmap.access_align = 32;
1632  fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1633  }
1634  }
1635  fb_info->pixmap.offset = 0;
1636 
1637  if (!fb_info->pixmap.blit_x)
1638  fb_info->pixmap.blit_x = ~(u32)0;
1639 
1640  if (!fb_info->pixmap.blit_y)
1641  fb_info->pixmap.blit_y = ~(u32)0;
1642 
1643  if (!fb_info->modelist.prev || !fb_info->modelist.next)
1644  INIT_LIST_HEAD(&fb_info->modelist);
1645 
1646  fb_var_to_videomode(&mode, &fb_info->var);
1647  fb_add_videomode(&mode, &fb_info->modelist);
1648  registered_fb[i] = fb_info;
1649 
1650  event.info = fb_info;
1651  if (!lock_fb_info(fb_info))
1652  return -ENODEV;
1654  unlock_fb_info(fb_info);
1655  return 0;
1656 }
1657 
1658 static int do_unregister_framebuffer(struct fb_info *fb_info)
1659 {
1660  struct fb_event event;
1661  int i, ret = 0;
1662 
1663  i = fb_info->node;
1664  if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1665  return -EINVAL;
1666 
1667  if (!lock_fb_info(fb_info))
1668  return -ENODEV;
1669  event.info = fb_info;
1671  unlock_fb_info(fb_info);
1672 
1673  if (ret)
1674  return -EINVAL;
1675 
1676  unlink_framebuffer(fb_info);
1677  if (fb_info->pixmap.addr &&
1678  (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1679  kfree(fb_info->pixmap.addr);
1680  fb_destroy_modelist(&fb_info->modelist);
1681  registered_fb[i] = NULL;
1683  fb_cleanup_device(fb_info);
1684  event.info = fb_info;
1686 
1687  /* this may free fb info */
1688  put_fb_info(fb_info);
1689  return 0;
1690 }
1691 
1692 int unlink_framebuffer(struct fb_info *fb_info)
1693 {
1694  int i;
1695 
1696  i = fb_info->node;
1697  if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1698  return -EINVAL;
1699 
1700  if (fb_info->dev) {
1701  device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1702  fb_info->dev = NULL;
1703  }
1704  return 0;
1705 }
1707 
1708 void remove_conflicting_framebuffers(struct apertures_struct *a,
1709  const char *name, bool primary)
1710 {
1711  mutex_lock(&registration_lock);
1712  do_remove_conflicting_framebuffers(a, name, primary);
1713  mutex_unlock(&registration_lock);
1714 }
1716 
1726 int
1727 register_framebuffer(struct fb_info *fb_info)
1728 {
1729  int ret;
1730 
1731  mutex_lock(&registration_lock);
1732  ret = do_register_framebuffer(fb_info);
1733  mutex_unlock(&registration_lock);
1734 
1735  return ret;
1736 }
1737 
1754 int
1755 unregister_framebuffer(struct fb_info *fb_info)
1756 {
1757  int ret;
1758 
1759  mutex_lock(&registration_lock);
1760  ret = do_unregister_framebuffer(fb_info);
1761  mutex_unlock(&registration_lock);
1762 
1763  return ret;
1764 }
1765 
1775 void fb_set_suspend(struct fb_info *info, int state)
1776 {
1777  struct fb_event event;
1778 
1779  event.info = info;
1780  if (state) {
1782  info->state = FBINFO_STATE_SUSPENDED;
1783  } else {
1784  info->state = FBINFO_STATE_RUNNING;
1786  }
1787 }
1788 
1798 static int __init
1799 fbmem_init(void)
1800 {
1801  proc_create("fb", 0, NULL, &fb_proc_fops);
1802 
1803  if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
1804  printk("unable to get major %d for fb devs\n", FB_MAJOR);
1805 
1806  fb_class = class_create(THIS_MODULE, "graphics");
1807  if (IS_ERR(fb_class)) {
1808  printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
1809  fb_class = NULL;
1810  }
1811  return 0;
1812 }
1813 
1814 #ifdef MODULE
1815 module_init(fbmem_init);
1816 static void __exit
1817 fbmem_exit(void)
1818 {
1819  remove_proc_entry("fb", NULL);
1820  class_destroy(fb_class);
1821  unregister_chrdev(FB_MAJOR, "fb");
1822 }
1823 
1824 module_exit(fbmem_exit);
1825 MODULE_LICENSE("GPL");
1826 MODULE_DESCRIPTION("Framebuffer base");
1827 #else
1828 subsys_initcall(fbmem_init);
1829 #endif
1830 
1831 int fb_new_modelist(struct fb_info *info)
1832 {
1833  struct fb_event event;
1834  struct fb_var_screeninfo var = info->var;
1835  struct list_head *pos, *n;
1836  struct fb_modelist *modelist;
1837  struct fb_videomode *m, mode;
1838  int err = 1;
1839 
1840  list_for_each_safe(pos, n, &info->modelist) {
1841  modelist = list_entry(pos, struct fb_modelist, list);
1842  m = &modelist->mode;
1843  fb_videomode_to_var(&var, m);
1844  var.activate = FB_ACTIVATE_TEST;
1845  err = fb_set_var(info, &var);
1846  fb_var_to_videomode(&mode, &var);
1847  if (err || !fb_mode_is_equal(m, &mode)) {
1848  list_del(pos);
1849  kfree(pos);
1850  }
1851  }
1852 
1853  err = 1;
1854 
1855  if (!list_empty(&info->modelist)) {
1856  if (!lock_fb_info(info))
1857  return -ENODEV;
1858  event.info = info;
1860  unlock_fb_info(info);
1861  }
1862 
1863  return err;
1864 }
1865 
1866 static char *video_options[FB_MAX] __read_mostly;
1867 static int ofonly __read_mostly;
1868 
1878 int fb_get_options(char *name, char **option)
1879 {
1880  char *opt, *options = NULL;
1881  int retval = 0;
1882  int name_len = strlen(name), i;
1883 
1884  if (name_len && ofonly && strncmp(name, "offb", 4))
1885  retval = 1;
1886 
1887  if (name_len && !retval) {
1888  for (i = 0; i < FB_MAX; i++) {
1889  if (video_options[i] == NULL)
1890  continue;
1891  if (!video_options[i][0])
1892  continue;
1893  opt = video_options[i];
1894  if (!strncmp(name, opt, name_len) &&
1895  opt[name_len] == ':')
1896  options = opt + name_len + 1;
1897  }
1898  }
1899  if (options && !strncmp(options, "off", 3))
1900  retval = 1;
1901 
1902  if (option)
1903  *option = options;
1904 
1905  return retval;
1906 }
1907 
1908 #ifndef MODULE
1909 
1922 static int __init video_setup(char *options)
1923 {
1924  int i, global = 0;
1925 
1926  if (!options || !*options)
1927  global = 1;
1928 
1929  if (!global && !strncmp(options, "ofonly", 6)) {
1930  ofonly = 1;
1931  global = 1;
1932  }
1933 
1934  if (!global && !strchr(options, ':')) {
1936  global = 1;
1937  }
1938 
1939  if (!global) {
1940  for (i = 0; i < FB_MAX; i++) {
1941  if (video_options[i] == NULL) {
1942  video_options[i] = options;
1943  break;
1944  }
1945 
1946  }
1947  }
1948 
1949  return 1;
1950 }
1951 __setup("video=", video_setup);
1952 #endif
1953 
1954  /*
1955  * Visible symbols for modules
1956  */
1957 
1960 EXPORT_SYMBOL(num_registered_fb);
1961 EXPORT_SYMBOL(registered_fb);
1969 
1970 MODULE_LICENSE("GPL");