2 * linux/drivers/video/fbmem.c
4 * Copyright (C) 1994 Martin Schaller
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
11 #include <linux/config.h>
12 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/errno.h>
16 #include <linux/sched.h>
17 #include <linux/kernel.h>
18 #include <linux/major.h>
19 #include <linux/malloc.h>
20 #include <linux/mman.h>
21 #include <linux/tty.h>
22 #include <linux/console.h>
23 #include <linux/console_struct.h>
24 #include <linux/init.h>
25 #include <linux/proc_fs.h>
27 #include <linux/kmod.h>
30 #if defined(__mc68000__) || defined(CONFIG_APUS)
31 #include <asm/setup.h>
36 #include <asm/uaccess.h>
38 #include <asm/pgtable.h>
44 * Frame buffer device initialization and setup routines
47 extern int acornfb_init(void);
48 extern int acornfb_setup(char*);
49 extern int amifb_init(void);
50 extern int amifb_setup(char*);
51 extern int atafb_init(void);
52 extern int atafb_setup(char*);
53 extern int macfb_init(void);
54 extern int macfb_setup(char*);
55 extern int cyberfb_init(void);
56 extern int cyberfb_setup(char*);
57 extern int pm2fb_init(void);
58 extern int pm2fb_setup(char*);
59 extern int cyber2000fb_init(void);
60 extern int cyber2000fb_setup(char*);
61 extern int retz3fb_init(void);
62 extern int retz3fb_setup(char*);
63 extern int clgenfb_init(void);
64 extern int clgenfb_setup(char*);
65 extern int vfb_init(void);
66 extern int vfb_setup(char*);
67 extern int offb_init(void);
68 extern int offb_setup(char*);
69 extern int atyfb_init(void);
70 extern int atyfb_setup(char*);
71 extern int igafb_init(void);
72 extern int igafb_setup(char*);
73 extern int imsttfb_init(void);
74 extern int imsttfb_setup(char*);
75 extern int dnfb_init(void);
76 extern int tgafb_init(void);
77 extern int tgafb_setup(char*);
78 extern int virgefb_init(void);
79 extern int virgefb_setup(char*);
80 extern int resolver_video_setup(char*);
81 extern int s3triofb_init(void);
82 extern int s3triofb_setup(char*);
83 extern int vesafb_init(void);
84 extern int vesafb_setup(char*);
85 extern int vga16fb_init(void);
86 extern int vga16fb_setup(char*);
87 extern int matroxfb_init(void);
88 extern int matroxfb_setup(char*);
89 extern int hpfb_init(void);
90 extern int hpfb_setup(char*);
91 extern int sbusfb_init(void);
92 extern int sbusfb_setup(char*);
93 extern int valkyriefb_init(void);
94 extern int valkyriefb_setup(char*);
95 extern int control_init(void);
96 extern int control_setup(char*);
97 extern int g364fb_init(void);
98 extern int fm2fb_init(void);
99 extern int fm2fb_setup(char*);
100 extern int q40fb_init(void);
101 extern int sgivwfb_init(void);
102 extern int sgivwfb_setup(char*);
103 extern int tdfxfb_init(void);
104 extern int tdfxfb_setup(char*);
110 } fb_drivers
[] __initdata
= {
111 #ifdef CONFIG_FB_3DFX
112 { "tdfx", tdfxfb_init
, tdfxfb_setup
},
114 #ifdef CONFIG_FB_SGIVW
115 { "sgivw", sgivwfb_init
, sgivwfb_setup
},
117 #ifdef CONFIG_FB_RETINAZ3
118 { "retz3", retz3fb_init
, retz3fb_setup
},
120 #ifdef CONFIG_FB_ACORN
121 { "acorn", acornfb_init
, acornfb_setup
},
123 #ifdef CONFIG_FB_AMIGA
124 { "amifb", amifb_init
, amifb_setup
},
126 #ifdef CONFIG_FB_ATARI
127 { "atafb", atafb_init
, atafb_setup
},
130 { "macfb", macfb_init
, macfb_setup
},
132 #ifdef CONFIG_FB_CYBER
133 { "cyber", cyberfb_init
, cyberfb_setup
},
135 #ifdef CONFIG_FB_CYBER2000
136 { "cyber2000", cyber2000fb_init
, cyber2000fb_setup
},
139 { "pm2fb", pm2fb_init
, pm2fb_setup
},
141 #ifdef CONFIG_FB_CLGEN
142 { "clgen", clgenfb_init
, clgenfb_setup
},
145 { "offb", offb_init
, offb_setup
},
147 #ifdef CONFIG_FB_SBUS
148 { "sbus", sbusfb_init
, sbusfb_setup
},
151 { "atyfb", atyfb_init
, atyfb_setup
},
154 { "igafb", igafb_init
, igafb_setup
},
156 #ifdef CONFIG_FB_IMSTT
157 { "imsttfb", imsttfb_init
, imsttfb_setup
},
160 { "apollo", dnfb_init
, NULL
},
163 { "q40fb", q40fb_init
, NULL
},
165 #ifdef CONFIG_FB_S3TRIO
166 { "s3trio", s3triofb_init
, s3triofb_setup
},
169 { "tga", tgafb_init
, tgafb_setup
},
171 #ifdef CONFIG_FB_VIRGE
172 { "virge", virgefb_init
, virgefb_setup
},
174 #ifdef CONFIG_FB_VESA
175 { "vesa", vesafb_init
, vesafb_setup
},
177 #ifdef CONFIG_FB_VGA16
178 { "vga16", vga16fb_init
, vga16fb_setup
},
180 #ifdef CONFIG_FB_MATROX
181 { "matrox", matroxfb_init
, matroxfb_setup
},
183 #ifdef CONFIG_FB_HP300
184 { "hpfb", hpfb_init
, hpfb_setup
},
186 #ifdef CONFIG_FB_CONTROL
187 { "controlfb", control_init
, control_setup
},
189 #ifdef CONFIG_FB_VALKYRIE
190 { "valkyriefb", valkyriefb_init
, valkyriefb_setup
},
192 #ifdef CONFIG_FB_G364
193 { "g364", g364fb_init
, NULL
},
196 { "fm2fb", fm2fb_init
, fm2fb_setup
},
198 #ifdef CONFIG_GSP_RESOLVER
199 /* Not a real frame buffer device... */
200 { "resolver", NULL
, resolver_video_setup
},
202 #ifdef CONFIG_FB_VIRTUAL
203 /* Must be last to avoid that vfb becomes your primary display */
204 { "vfb", vfb_init
, vfb_setup
},
208 #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
210 extern const char *global_mode_option
;
212 static initcall_t pref_init_funcs
[FB_MAX
];
213 static int num_pref_init_funcs __initdata
= 0;
216 #define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
217 #define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1))
219 struct fb_info
*registered_fb
[FB_MAX
];
220 int num_registered_fb
= 0;
221 int fbcon_softback_size
= 32768;
223 char con2fb_map
[MAX_NR_CONSOLES
];
225 static int first_fb_vc
= 0;
226 static int last_fb_vc
= MAX_NR_CONSOLES
-1;
227 static int fbcon_is_default
= 1;
229 static int PROC_CONSOLE(const struct fb_info
*info
)
233 if (info
->display_fg
!= NULL
)
234 fgc
= info
->display_fg
->vc_num
;
241 if (current
->tty
->driver
.type
!= TTY_DRIVER_TYPE_CONSOLE
)
242 /* XXX Should report error here? */
245 if (MINOR(current
->tty
->device
) < 1)
248 return MINOR(current
->tty
->device
) - 1;
251 static int fbmem_read_proc(char *buf
, char **start
, off_t offset
,
252 int len
, int *eof
, void *private)
257 for (fi
= registered_fb
; fi
< ®istered_fb
[FB_MAX
] && len
< 4000; fi
++)
259 len
+= sprintf(buf
+ len
, "%d %s\n",
260 GET_FB_IDX((*fi
)->node
),
262 *start
= buf
+ offset
;
263 return len
> offset
? len
- offset
: 0;
267 fb_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
269 unsigned long p
= *ppos
;
270 struct inode
*inode
= file
->f_dentry
->d_inode
;
271 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
272 struct fb_info
*info
= registered_fb
[fbidx
];
273 struct fb_ops
*fb
= info
->fbops
;
274 struct fb_fix_screeninfo fix
;
278 if (! fb
|| ! info
->disp
)
281 fb
->fb_get_fix(&fix
,PROC_CONSOLE(info
), info
);
282 base_addr
=info
->disp
->screen_base
;
283 copy_size
=(count
+ p
<= fix
.smem_len
? count
: fix
.smem_len
- p
);
284 if (copy_to_user(buf
, base_addr
+p
, copy_size
))
291 fb_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
293 unsigned long p
= *ppos
;
294 struct inode
*inode
= file
->f_dentry
->d_inode
;
295 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
296 struct fb_info
*info
= registered_fb
[fbidx
];
297 struct fb_ops
*fb
= info
->fbops
;
298 struct fb_fix_screeninfo fix
;
302 if (! fb
|| ! info
->disp
)
305 fb
->fb_get_fix(&fix
, PROC_CONSOLE(info
), info
);
306 base_addr
=info
->disp
->screen_base
;
307 copy_size
=(count
+ p
<= fix
.smem_len
? count
: fix
.smem_len
- p
);
308 if (copy_from_user(base_addr
+p
, buf
, copy_size
))
310 file
->f_pos
+= copy_size
;
315 static int set_all_vcs(int fbidx
, struct fb_ops
*fb
,
316 struct fb_var_screeninfo
*var
, struct fb_info
*info
)
320 var
->activate
|= FB_ACTIVATE_TEST
;
321 err
= fb
->fb_set_var(var
, PROC_CONSOLE(info
), info
);
322 var
->activate
&= ~FB_ACTIVATE_TEST
;
325 for (unit
= 0; unit
< MAX_NR_CONSOLES
; unit
++)
326 if (fb_display
[unit
].conp
&& con2fb_map
[unit
] == fbidx
)
327 fb
->fb_set_var(var
, unit
, info
);
331 static void set_con2fb_map(int unit
, int newidx
)
333 int oldidx
= con2fb_map
[unit
];
334 struct fb_info
*oldfb
, *newfb
;
335 struct vc_data
*conp
;
337 unsigned short fontwidth
, fontheight
, fontwidthlog
, fontheightlog
;
340 if (newidx
!= con2fb_map
[unit
]) {
341 oldfb
= registered_fb
[oldidx
];
342 newfb
= registered_fb
[newidx
];
343 if (newfb
->fbops
->fb_open(newfb
,0))
345 oldfb
->fbops
->fb_release(oldfb
,0);
346 conp
= fb_display
[unit
].conp
;
347 fontdata
= fb_display
[unit
].fontdata
;
348 fontwidth
= fb_display
[unit
]._fontwidth
;
349 fontheight
= fb_display
[unit
]._fontheight
;
350 fontwidthlog
= fb_display
[unit
]._fontwidthlog
;
351 fontheightlog
= fb_display
[unit
]._fontheightlog
;
352 userfont
= fb_display
[unit
].userfont
;
353 con2fb_map
[unit
] = newidx
;
354 fb_display
[unit
] = *(newfb
->disp
);
355 fb_display
[unit
].conp
= conp
;
356 fb_display
[unit
].fontdata
= fontdata
;
357 fb_display
[unit
]._fontwidth
= fontwidth
;
358 fb_display
[unit
]._fontheight
= fontheight
;
359 fb_display
[unit
]._fontwidthlog
= fontwidthlog
;
360 fb_display
[unit
]._fontheightlog
= fontheightlog
;
361 fb_display
[unit
].userfont
= userfont
;
362 fb_display
[unit
].fb_info
= newfb
;
363 if (!newfb
->changevar
)
364 newfb
->changevar
= oldfb
->changevar
;
365 /* tell console var has changed */
366 if (newfb
->changevar
)
367 newfb
->changevar(unit
);
372 static void try_to_load(int fb
)
376 sprintf(modname
, "fb%d", fb
);
377 request_module(modname
);
379 #endif /* CONFIG_KMOD */
382 fb_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
385 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
386 struct fb_info
*info
= registered_fb
[fbidx
];
387 struct fb_ops
*fb
= info
->fbops
;
389 struct fb_var_screeninfo var
;
390 struct fb_fix_screeninfo fix
;
391 struct fb_con2fbmap con2fb
;
397 case FBIOGET_VSCREENINFO
:
398 if ((i
= fb
->fb_get_var(&var
, PROC_CONSOLE(info
), info
)))
400 return copy_to_user((void *) arg
, &var
,
401 sizeof(var
)) ? -EFAULT
: 0;
402 case FBIOPUT_VSCREENINFO
:
403 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
405 i
= var
.activate
& FB_ACTIVATE_ALL
406 ? set_all_vcs(fbidx
, fb
, &var
, info
)
407 : fb
->fb_set_var(&var
, PROC_CONSOLE(info
), info
);
410 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
413 case FBIOGET_FSCREENINFO
:
414 if ((i
= fb
->fb_get_fix(&fix
, PROC_CONSOLE(info
), info
)))
416 return copy_to_user((void *) arg
, &fix
, sizeof(fix
)) ?
419 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
421 return (fb
->fb_set_cmap(&cmap
, 0, PROC_CONSOLE(info
), info
));
423 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
425 return (fb
->fb_get_cmap(&cmap
, 0, PROC_CONSOLE(info
), info
));
426 case FBIOPAN_DISPLAY
:
427 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
429 if ((i
=fb
->fb_pan_display(&var
, PROC_CONSOLE(info
), info
)))
431 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
434 case FBIOGET_CON2FBMAP
:
435 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
437 if (con2fb
.console
< 1 || con2fb
.console
> MAX_NR_CONSOLES
)
439 con2fb
.framebuffer
= con2fb_map
[con2fb
.console
-1];
440 return copy_to_user((void *)arg
, &con2fb
,
441 sizeof(con2fb
)) ? -EFAULT
: 0;
442 case FBIOPUT_CON2FBMAP
:
443 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
445 if (con2fb
.console
< 0 || con2fb
.console
> MAX_NR_CONSOLES
)
447 if (con2fb
.framebuffer
< 0 || con2fb
.framebuffer
>= FB_MAX
)
450 if (!registered_fb
[con2fb
.framebuffer
])
451 try_to_load(con2fb
.framebuffer
);
452 #endif /* CONFIG_KMOD */
453 if (!registered_fb
[con2fb
.framebuffer
])
455 if (con2fb
.console
!= 0)
456 set_con2fb_map(con2fb
.console
-1, con2fb
.framebuffer
);
459 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
460 set_con2fb_map(i
, con2fb
.framebuffer
);
463 if (info
->blank
== 0)
465 (*info
->blank
)(arg
, info
);
468 return fb
->fb_ioctl(inode
, file
, cmd
, arg
, PROC_CONSOLE(info
),
474 fb_mmap(struct file
*file
, struct vm_area_struct
* vma
)
476 int fbidx
= GET_FB_IDX(file
->f_dentry
->d_inode
->i_rdev
);
477 struct fb_info
*info
= registered_fb
[fbidx
];
478 struct fb_ops
*fb
= info
->fbops
;
479 struct fb_fix_screeninfo fix
;
480 struct fb_var_screeninfo var
;
487 return fb
->fb_mmap(info
, file
, vma
);
489 #if defined(__sparc__)
490 /* Should never get here, all fb drivers should have their own
496 fb
->fb_get_fix(&fix
, PROC_CONSOLE(info
), info
);
498 /* frame buffer memory */
499 start
= fix
.smem_start
;
500 len
= (start
& ~PAGE_MASK
)+fix
.smem_len
;
502 len
= (len
+~PAGE_MASK
) & PAGE_MASK
;
503 if (vma
->vm_offset
>= len
) {
504 /* memory mapped io */
505 vma
->vm_offset
-= len
;
506 fb
->fb_get_var(&var
, PROC_CONSOLE(info
), info
);
509 start
= fix
.mmio_start
;
510 len
= (start
& ~PAGE_MASK
)+fix
.mmio_len
;
512 len
= (len
+~PAGE_MASK
) & PAGE_MASK
;
514 if ((vma
->vm_end
- vma
->vm_start
+ vma
->vm_offset
) > len
)
516 vma
->vm_offset
+= start
;
517 if (vma
->vm_offset
& ~PAGE_MASK
)
519 #if defined(__mc68000__)
520 if (CPU_IS_020_OR_030
)
521 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE030
;
522 if (CPU_IS_040_OR_060
) {
523 pgprot_val(vma
->vm_page_prot
) &= _CACHEMASK040
;
524 /* Use no-cache mode, serialized */
525 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE_S
;
527 #elif defined(__powerpc__)
528 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NO_CACHE
|_PAGE_GUARDED
;
529 #elif defined(__alpha__)
530 /* Caching is off in the I/O space quadrant by design. */
531 #elif defined(__i386__)
532 if (boot_cpu_data
.x86
> 3)
533 pgprot_val(vma
->vm_page_prot
) |= _PAGE_PCD
;
534 #elif defined(__mips__)
535 pgprot_val(vma
->vm_page_prot
) &= ~_CACHE_MASK
;
536 pgprot_val(vma
->vm_page_prot
) |= _CACHE_UNCACHED
;
537 #elif defined(__arm__)
538 #if defined(CONFIG_CPU_32) && !defined(CONFIG_ARCH_ACORN)
539 /* On Acorn architectures, we want to keep the framebuffer
542 pgprot_val(vma
->vm_page_prot
) &= ~(PTE_CACHEABLE
| PTE_BUFFERABLE
);
545 #warning What do we have to do here??
547 if (io_remap_page_range(vma
->vm_start
, vma
->vm_offset
,
548 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
552 #endif /* defined(__sparc__) */
556 fb_open(struct inode
*inode
, struct file
*file
)
558 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
559 struct fb_info
*info
;
562 if (!(info
= registered_fb
[fbidx
]))
564 #endif /* CONFIG_KMOD */
565 if (!(info
= registered_fb
[fbidx
]))
567 return info
->fbops
->fb_open(info
,1);
571 fb_release(struct inode
*inode
, struct file
*file
)
573 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
574 struct fb_info
*info
= registered_fb
[fbidx
];
576 info
->fbops
->fb_release(info
,1);
580 static struct file_operations fb_fops
= {
583 fb_write
, /* write */
586 fb_ioctl
, /* ioctl */
590 fb_release
, /* release */
595 register_framebuffer(struct fb_info
*fb_info
)
598 static int fb_ever_opened
[FB_MAX
];
599 static int first
= 1;
601 if (num_registered_fb
== FB_MAX
)
604 for (i
= 0 ; i
< FB_MAX
; i
++)
605 if (!registered_fb
[i
])
607 fb_info
->node
=GET_INODE(i
);
608 registered_fb
[i
] = fb_info
;
609 if (!fb_ever_opened
[i
]) {
611 * We assume initial frame buffer devices can be opened this
614 for (j
= 0; j
< MAX_NR_CONSOLES
; j
++)
615 if (con2fb_map
[j
] == i
)
616 fb_info
->fbops
->fb_open(fb_info
,0);
617 fb_ever_opened
[i
] = 1;
622 take_over_console(&fb_con
, first_fb_vc
, last_fb_vc
, fbcon_is_default
);
629 unregister_framebuffer(const struct fb_info
*fb_info
)
633 i
= GET_FB_IDX(fb_info
->node
);
634 for (j
= 0; j
< MAX_NR_CONSOLES
; j
++)
635 if (con2fb_map
[j
] == i
)
637 if (!registered_fb
[i
])
639 registered_fb
[i
]=NULL
;
644 static struct proc_dir_entry
*proc_fbmem
;
651 proc_fbmem
= create_proc_entry("fb", 0, 0);
653 proc_fbmem
->read_proc
= fbmem_read_proc
;
655 if (register_chrdev(FB_MAJOR
,"fb",&fb_fops
))
656 printk("unable to get major %d for fb devs\n", FB_MAJOR
);
659 * Probe for all builtin frame buffer devices
661 for (i
= 0; i
< num_pref_init_funcs
; i
++)
662 pref_init_funcs
[i
]();
664 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++)
665 if (fb_drivers
[i
].init
)
666 fb_drivers
[i
].init();
670 int fbmon_valid_timings(u_int pixclock
, u_int htotal
, u_int vtotal
,
671 const struct fb_info
*fb_info
)
675 * long long divisions .... $#%%#$
677 unsigned long long hpicos
, vpicos
;
678 const unsigned long long _1e12
= 1000000000000ULL;
679 const struct fb_monspecs
*monspecs
= &fb_info
->monspecs
;
681 hpicos
= (unsigned long long)htotal
*(unsigned long long)pixclock
;
682 vpicos
= (unsigned long long)vtotal
*(unsigned long long)hpicos
;
686 if (monspecs
->hfmin
== 0)
689 if (hpicos
*monspecs
->hfmin
> _1e12
|| hpicos
*monspecs
->hfmax
< _1e12
||
690 vpicos
*monspecs
->vfmin
> _1e12
|| vpicos
*monspecs
->vfmax
< _1e12
)
696 int fbmon_dpms(const struct fb_info
*fb_info
)
698 return fb_info
->monspecs
.dpms
;
703 * Command line options
706 int __init
video_setup(char *options
)
710 if (!options
|| !*options
)
713 if (!strncmp(options
, "scrollback:", 11)) {
716 fbcon_softback_size
= simple_strtoul(options
, &options
, 0);
717 if (*options
== 'k' || *options
== 'K') {
718 fbcon_softback_size
*= 1024;
728 if (!strncmp(options
, "map:", 4)) {
731 for (i
= 0, j
= 0; i
< MAX_NR_CONSOLES
; i
++) {
734 con2fb_map
[i
] = (options
[j
++]-'0') % FB_MAX
;
739 if (!strncmp(options
, "vc:", 3)) {
742 first_fb_vc
= simple_strtoul(options
, &options
, 10) - 1;
745 if (*options
++ == '-')
746 last_fb_vc
= simple_strtoul(options
, &options
, 10) - 1;
747 fbcon_is_default
= 0;
750 if (num_pref_init_funcs
== FB_MAX
)
753 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++) {
754 j
= strlen(fb_drivers
[i
].name
);
755 if (!strncmp(options
, fb_drivers
[i
].name
, j
) &&
757 if (!strcmp(options
+j
+1, "off"))
758 fb_drivers
[i
].init
= NULL
;
760 if (fb_drivers
[i
].init
) {
761 pref_init_funcs
[num_pref_init_funcs
++] =
763 fb_drivers
[i
].init
= NULL
;
765 if (fb_drivers
[i
].setup
)
766 fb_drivers
[i
].setup(options
+j
+1);
773 * If we get here no fb was specified.
774 * We consider the argument to be a global video mode option.
776 global_mode_option
= options
;
780 __setup("video=", video_setup
);
783 * Visible symbols for modules
786 EXPORT_SYMBOL(register_framebuffer
);
787 EXPORT_SYMBOL(unregister_framebuffer
);