2 * linux/drivers/char/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>
26 #include <linux/proc_fs.h>
29 #include <linux/kmod.h>
33 #include <asm/setup.h>
38 #include <asm/uaccess.h>
40 #include <asm/pgtable.h>
46 * Frame buffer device initialization and setup routines
49 extern unsigned long acornfb_init(void);
50 extern void acornfb_setup(char *options
, int *ints
);
51 extern void amifb_init(void);
52 extern void amifb_setup(char *options
, int *ints
);
53 extern void atafb_init(void);
54 extern void atafb_setup(char *options
, int *ints
);
55 extern void macfb_init(void);
56 extern void macfb_setup(char *options
, int *ints
);
57 extern void cyberfb_init(void);
58 extern void cyberfb_setup(char *options
, int *ints
);
59 extern void retz3fb_init(void);
60 extern void retz3fb_setup(char *options
, int *ints
);
61 extern void clgenfb_init(void);
62 extern void clgenfb_setup(char *options
, int *ints
);
63 extern void vfb_init(void);
64 extern void vfb_setup(char *options
, int *ints
);
65 extern void offb_init(void);
66 extern void offb_setup(char *options
, int *ints
);
67 extern void atyfb_init(void);
68 extern void atyfb_setup(char *options
, int *ints
);
69 extern void dnfb_init(void);
70 extern void tgafb_init(void);
71 extern void virgefb_init(void);
72 extern void virgefb_setup(char *options
, int *ints
);
73 extern void resolver_video_setup(char *options
, int *ints
);
74 extern void s3triofb_init(void);
75 extern void s3triofb_setup(char *options
, int *ints
);
76 extern void vgafb_init(void);
77 extern void vgafb_setup(char *options
, int *ints
);
78 extern void vesafb_init(void);
79 extern void vesafb_setup(char *options
, int *ints
);
80 extern void mdafb_init(void);
81 extern void mdafb_setup(char *options
, int *ints
);
82 extern void hpfb_init(void);
83 extern void hpfb_setup(char *options
, int *ints
);
84 extern void sbusfb_init(void);
85 extern void sbusfb_setup(char *options
, int *ints
);
90 void (*setup
)(char *options
, int *ints
);
91 } fb_drivers
[] __initdata
= {
92 #ifdef CONFIG_FB_RETINAZ3
93 { "retz3", retz3fb_init
, retz3fb_setup
},
95 #ifdef CONFIG_FB_ACORN
96 { "acorn", acornfb_init
, acornfb_setup
},
98 #ifdef CONFIG_FB_AMIGA
99 { "amifb", amifb_init
, amifb_setup
},
101 #ifdef CONFIG_FB_ATARI
102 { "atafb", atafb_init
, atafb_setup
},
105 { "macfb", macfb_init
, macfb_setup
},
107 #ifdef CONFIG_FB_CYBER
108 { "cyber", cyberfb_init
, cyberfb_setup
},
110 #ifdef CONFIG_FB_CLGEN
111 { "clgen", clgenfb_init
, clgenfb_setup
},
114 { "offb", offb_init
, offb_setup
},
117 { "atyfb", atyfb_init
, atyfb_setup
},
120 { "apollo", dnfb_init
, NULL
},
122 #ifdef CONFIG_FB_S3TRIO
123 { "s3trio", s3triofb_init
, s3triofb_setup
},
126 { "tga", tgafb_init
, NULL
},
128 #ifdef CONFIG_FB_VIRGE
129 { "virge", virgefb_init
, virgefb_setup
},
132 { "vga", vgafb_init
, vgafb_setup
},
134 #ifdef CONFIG_FB_VESA
135 { "vesa", vesafb_init
, vesafb_setup
},
138 { "mda", mdafb_init
, mdafb_setup
},
140 #ifdef CONFIG_FB_HP300
141 { "hpfb", hpfb_init
, hpfb_setup
},
143 #ifdef CONFIG_FB_SBUS
144 { "sbus", sbusfb_init
, sbusfb_setup
},
146 #ifdef CONFIG_GSP_RESOLVER
147 /* Not a real frame buffer device... */
148 { "resolver", NULL
, resolver_video_setup
},
150 #ifdef CONFIG_FB_VIRTUAL
151 /* Must be last to avoid that vfb becomes your primary display */
152 { "vfb", vfb_init
, vfb_setup
},
156 #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
158 static void (*pref_init_funcs
[FB_MAX
])(void);
159 static int num_pref_init_funcs __initdata
= 0;
162 #define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
163 #define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1))
165 struct fb_info
*registered_fb
[FB_MAX
];
166 int num_registered_fb
= 0;
168 char con2fb_map
[MAX_NR_CONSOLES
];
170 static inline int PROC_CONSOLE(void)
175 if (current
->tty
->driver
.type
!= TTY_DRIVER_TYPE_CONSOLE
)
176 /* XXX Should report error here? */
179 if (MINOR(current
->tty
->device
) < 1)
182 return MINOR(current
->tty
->device
) - 1;
185 #ifdef CONFIG_PROC_FS
186 static int fbmem_read_proc(char *buf
, char **start
, off_t offset
,
187 int len
, int *eof
, void *private)
192 for (fi
= registered_fb
; fi
< ®istered_fb
[FB_MAX
] && len
< 4000; fi
++)
194 len
+= sprintf(buf
+ len
, "%d %s\n",
195 GET_FB_IDX((*fi
)->node
),
197 *start
= buf
+ offset
;
198 return len
> offset
? len
- offset
: 0;
203 fb_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
205 unsigned long p
= *ppos
;
206 struct inode
*inode
= file
->f_dentry
->d_inode
;
207 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
208 struct fb_info
*info
= registered_fb
[fbidx
];
209 struct fb_ops
*fb
= info
->fbops
;
210 struct fb_fix_screeninfo fix
;
214 if (! fb
|| ! info
->disp
)
217 fb
->fb_get_fix(&fix
,PROC_CONSOLE(), info
);
218 base_addr
=info
->disp
->screen_base
;
219 copy_size
=(count
+ p
<= fix
.smem_len
? count
: fix
.smem_len
- p
);
220 if (copy_to_user(buf
, base_addr
+p
, copy_size
))
227 fb_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
229 unsigned long p
= *ppos
;
230 struct inode
*inode
= file
->f_dentry
->d_inode
;
231 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
232 struct fb_info
*info
= registered_fb
[fbidx
];
233 struct fb_ops
*fb
= info
->fbops
;
234 struct fb_fix_screeninfo fix
;
238 if (! fb
|| ! info
->disp
)
241 fb
->fb_get_fix(&fix
, PROC_CONSOLE(), info
);
242 base_addr
=info
->disp
->screen_base
;
243 copy_size
=(count
+ p
<= fix
.smem_len
? count
: fix
.smem_len
- p
);
244 if (copy_from_user(base_addr
+p
, buf
, copy_size
))
246 file
->f_pos
+= copy_size
;
251 static void set_con2fb_map(int unit
, int newidx
)
253 int oldidx
= con2fb_map
[unit
];
254 struct fb_info
*oldfb
, *newfb
;
255 struct vc_data
*conp
;
257 if (newidx
!= con2fb_map
[unit
]) {
258 oldfb
= registered_fb
[oldidx
];
259 newfb
= registered_fb
[newidx
];
260 if (newfb
->fbops
->fb_open(newfb
,0))
262 oldfb
->fbops
->fb_release(oldfb
,0);
263 conp
= fb_display
[unit
].conp
;
264 con2fb_map
[unit
] = newidx
;
265 fb_display
[unit
] = *(newfb
->disp
);
266 fb_display
[unit
].conp
= conp
;
267 fb_display
[unit
].fb_info
= newfb
;
268 if (!newfb
->changevar
)
269 newfb
->changevar
= oldfb
->changevar
;
270 /* tell console var has changed */
271 if (newfb
->changevar
)
272 newfb
->changevar(unit
);
277 static void try_to_load(int fb
)
281 sprintf(modname
, "fb%d", fb
);
282 request_module(modname
);
284 #endif /* CONFIG_KMOD */
287 fb_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
290 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
291 struct fb_info
*info
= registered_fb
[fbidx
];
292 struct fb_ops
*fb
= info
->fbops
;
294 struct fb_var_screeninfo var
;
295 struct fb_fix_screeninfo fix
;
296 struct fb_con2fbmap con2fb
;
302 case FBIOGET_VSCREENINFO
:
303 if ((i
= fb
->fb_get_var(&var
, PROC_CONSOLE(), info
)))
305 return copy_to_user((void *) arg
, &var
,
306 sizeof(var
)) ? -EFAULT
: 0;
307 case FBIOPUT_VSCREENINFO
:
308 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
310 if ((i
= fb
->fb_set_var(&var
, PROC_CONSOLE(), info
)))
312 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
315 case FBIOGET_FSCREENINFO
:
316 if ((i
= fb
->fb_get_fix(&fix
, PROC_CONSOLE(), info
)))
318 return copy_to_user((void *) arg
, &fix
, sizeof(fix
)) ?
321 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
323 return (fb
->fb_set_cmap(&cmap
, 0, PROC_CONSOLE(), info
));
325 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
327 return (fb
->fb_get_cmap(&cmap
, 0, PROC_CONSOLE(), info
));
328 case FBIOPAN_DISPLAY
:
329 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
331 if ((i
=fb
->fb_pan_display(&var
, PROC_CONSOLE(), info
)))
333 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
336 case FBIOGET_CON2FBMAP
:
337 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
339 if (con2fb
.console
< 1 || con2fb
.console
> MAX_NR_CONSOLES
)
341 con2fb
.framebuffer
= con2fb_map
[con2fb
.console
-1];
342 return copy_to_user((void *)arg
, &con2fb
,
343 sizeof(con2fb
)) ? -EFAULT
: 0;
344 case FBIOPUT_CON2FBMAP
:
345 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
347 if (con2fb
.console
< 0 || con2fb
.console
> MAX_NR_CONSOLES
)
349 if (con2fb
.framebuffer
< 0 || con2fb
.framebuffer
>= FB_MAX
)
352 if (!registered_fb
[con2fb
.framebuffer
])
353 try_to_load(con2fb
.framebuffer
);
354 #endif /* CONFIG_KMOD */
355 if (!registered_fb
[con2fb
.framebuffer
])
357 if (con2fb
.console
!= 0)
358 set_con2fb_map(con2fb
.console
-1, con2fb
.framebuffer
);
361 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
362 set_con2fb_map(i
, con2fb
.framebuffer
);
365 return fb
->fb_ioctl(inode
, file
, cmd
, arg
, PROC_CONSOLE(),
371 fb_mmap(struct file
*file
, struct vm_area_struct
* vma
)
373 int fbidx
= GET_FB_IDX(file
->f_dentry
->d_inode
->i_rdev
);
374 struct fb_info
*info
= registered_fb
[fbidx
];
375 struct fb_ops
*fb
= info
->fbops
;
376 struct fb_fix_screeninfo fix
;
377 struct fb_var_screeninfo var
;
384 return fb
->fb_mmap(info
, file
, vma
);
385 fb
->fb_get_fix(&fix
, PROC_CONSOLE(), info
);
387 /* frame buffer memory */
388 start
= (unsigned long)fix
.smem_start
;
389 len
= (start
& ~PAGE_MASK
)+fix
.smem_len
;
391 len
= (len
+~PAGE_MASK
) & PAGE_MASK
;
392 if (vma
->vm_offset
>= len
) {
393 /* memory mapped io */
394 vma
->vm_offset
-= len
;
395 fb
->fb_get_var(&var
, PROC_CONSOLE(), info
);
398 start
= (unsigned long)fix
.mmio_start
;
399 len
= (start
& ~PAGE_MASK
)+fix
.mmio_len
;
401 len
= (len
+~PAGE_MASK
) & PAGE_MASK
;
403 if ((vma
->vm_end
- vma
->vm_start
+ vma
->vm_offset
) > len
)
405 vma
->vm_offset
+= start
;
406 if (vma
->vm_offset
& ~PAGE_MASK
)
408 #if defined(__mc68000__)
409 if (CPU_IS_020_OR_030
)
410 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE030
;
411 if (CPU_IS_040_OR_060
) {
412 pgprot_val(vma
->vm_page_prot
) &= _CACHEMASK040
;
413 /* Use no-cache mode, serialized */
414 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE_S
;
416 #elif defined(__powerpc__)
417 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NO_CACHE
|_PAGE_GUARDED
;
418 #elif defined(__alpha__)
419 /* Caching is off in the I/O space quadrant by design. */
420 #elif defined(__sparc__)
421 /* Should never get here, all fb drivers should have their own
423 #elif defined(__i386__)
424 if (boot_cpu_data
.x86
> 3)
425 pgprot_val(vma
->vm_page_prot
) |= _PAGE_PCD
;
427 #warning What do we have to do here??
429 if (remap_page_range(vma
->vm_start
, vma
->vm_offset
,
430 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
438 fb_open(struct inode
*inode
, struct file
*file
)
440 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
441 struct fb_info
*info
;
444 if (!(info
= registered_fb
[fbidx
]))
446 #endif /* CONFIG_KMOD */
447 if (!(info
= registered_fb
[fbidx
]))
449 return info
->fbops
->fb_open(info
,1);
453 fb_release(struct inode
*inode
, struct file
*file
)
455 int fbidx
= GET_FB_IDX(inode
->i_rdev
);
456 struct fb_info
*info
= registered_fb
[fbidx
];
458 info
->fbops
->fb_release(info
,1);
462 static struct file_operations fb_fops
= {
465 fb_write
, /* write */
468 fb_ioctl
, /* ioctl */
472 fb_release
, /* release */
477 register_framebuffer(struct fb_info
*fb_info
)
480 static int fb_ever_opened
[FB_MAX
];
481 static int first
= 1;
483 if (num_registered_fb
== FB_MAX
)
486 for (i
= 0 ; i
< FB_MAX
; i
++)
487 if (!registered_fb
[i
])
489 fb_info
->node
=GET_INODE(i
);
490 registered_fb
[i
] = fb_info
;
491 if (!fb_ever_opened
[i
]) {
493 * We assume initial frame buffer devices can be opened this
496 for (j
= 0; j
< MAX_NR_CONSOLES
; j
++)
497 if (con2fb_map
[j
] == i
)
498 fb_info
->fbops
->fb_open(fb_info
,0);
499 fb_ever_opened
[i
] = 1;
504 take_over_console(&fb_con
, 0, MAX_NR_CONSOLES
-1, 1);
511 unregister_framebuffer(const struct fb_info
*fb_info
)
515 i
= GET_FB_IDX(fb_info
->node
);
516 for (j
= 0; j
< MAX_NR_CONSOLES
; j
++)
517 if (con2fb_map
[j
] == i
)
519 if (!registered_fb
[i
])
521 registered_fb
[i
]=NULL
;
526 #ifdef CONFIG_PROC_FS
527 static struct proc_dir_entry
*proc_fbmem
;
535 #ifdef CONFIG_PROC_FS
536 proc_fbmem
= create_proc_entry("fb", 0, 0);
538 proc_fbmem
->read_proc
= fbmem_read_proc
;
541 if (register_chrdev(FB_MAJOR
,"fb",&fb_fops
))
542 printk("unable to get major %d for fb devs\n", FB_MAJOR
);
545 * Probe for all builtin frame buffer devices
547 for (i
= 0; i
< num_pref_init_funcs
; i
++)
548 pref_init_funcs
[i
]();
550 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++)
551 if (fb_drivers
[i
].init
)
552 fb_drivers
[i
].init();
556 int fbmon_valid_timings(u_int pixclock
, u_int htotal
, u_int vtotal
,
557 const struct fb_info
*fb_info
)
561 * long long divisions .... $#%%#$
563 unsigned long long hpicos
, vpicos
;
564 const unsigned long long _1e12
= 1000000000000ULL;
565 const struct fb_monspecs
*monspecs
= &fb_info
->monspecs
;
567 hpicos
= (unsigned long long)htotal
*(unsigned long long)pixclock
;
568 vpicos
= (unsigned long long)vtotal
*(unsigned long long)hpicos
;
572 if (monspecs
->hfmin
== 0)
575 if (hpicos
*monspecs
->hfmin
> _1e12
|| hpicos
*monspecs
->hfmax
< _1e12
||
576 vpicos
*monspecs
->vfmin
> _1e12
|| vpicos
*monspecs
->vfmax
< _1e12
)
582 int fbmon_dpms(const struct fb_info
*fb_info
)
584 return fb_info
->monspecs
.dpms
;
589 * Command line options
592 __initfunc(void video_setup(char *options
, int *ints
))
596 if (!options
|| !*options
)
599 if (!strncmp(options
, "map:", 4)) {
602 for (i
= 0, j
= 0; i
< MAX_NR_CONSOLES
; i
++) {
605 con2fb_map
[i
] = (options
[j
++]-'0') % FB_MAX
;
610 if (num_pref_init_funcs
== FB_MAX
)
613 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++) {
614 j
= strlen(fb_drivers
[i
].name
);
615 if (!strncmp(options
, fb_drivers
[i
].name
, j
) &&
617 if (!strcmp(options
+j
+1, "off"))
618 fb_drivers
[i
].init
= NULL
;
620 if (fb_drivers
[i
].init
) {
621 pref_init_funcs
[num_pref_init_funcs
++] =
623 fb_drivers
[i
].init
= NULL
;
625 if (fb_drivers
[i
].setup
)
626 fb_drivers
[i
].setup(options
+j
+1, ints
);
632 * If we get here no fb was specified and we default to pass the
633 * options to the first frame buffer that has an init and a setup
636 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++) {
637 if (fb_drivers
[i
].init
&& fb_drivers
[i
].setup
) {
638 pref_init_funcs
[num_pref_init_funcs
++] =
640 fb_drivers
[i
].init
= NULL
;
642 fb_drivers
[i
].setup(options
, ints
);
650 * Visible symbols for modules
653 EXPORT_SYMBOL(register_framebuffer
);
654 EXPORT_SYMBOL(unregister_framebuffer
);