* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / video / fbmem.c
blob24504b17a84d3f0124b6eb53a9308faee813853d
1 /*
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
8 * for more details.
9 */
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>
26 #ifdef CONFIG_KMOD
27 #include <linux/kmod.h>
28 #endif
30 #if defined(__mc68000__) || defined(CONFIG_APUS)
31 #include <asm/setup.h>
32 #endif
33 #ifdef __powerpc__
34 #include <asm/io.h>
35 #endif
36 #include <asm/uaccess.h>
37 #include <asm/page.h>
38 #include <asm/pgtable.h>
40 #include <linux/fb.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*);
106 static struct {
107 const char *name;
108 int (*init)(void);
109 int (*setup)(char*);
110 } fb_drivers[] __initdata = {
111 #ifdef CONFIG_FB_3DFX
112 { "tdfx", tdfxfb_init, tdfxfb_setup },
113 #endif
114 #ifdef CONFIG_FB_SGIVW
115 { "sgivw", sgivwfb_init, sgivwfb_setup },
116 #endif
117 #ifdef CONFIG_FB_RETINAZ3
118 { "retz3", retz3fb_init, retz3fb_setup },
119 #endif
120 #ifdef CONFIG_FB_ACORN
121 { "acorn", acornfb_init, acornfb_setup },
122 #endif
123 #ifdef CONFIG_FB_AMIGA
124 { "amifb", amifb_init, amifb_setup },
125 #endif
126 #ifdef CONFIG_FB_ATARI
127 { "atafb", atafb_init, atafb_setup },
128 #endif
129 #ifdef CONFIG_FB_MAC
130 { "macfb", macfb_init, macfb_setup },
131 #endif
132 #ifdef CONFIG_FB_CYBER
133 { "cyber", cyberfb_init, cyberfb_setup },
134 #endif
135 #ifdef CONFIG_FB_CYBER2000
136 { "cyber2000", cyber2000fb_init, cyber2000fb_setup },
137 #endif
138 #ifdef CONFIG_FB_PM2
139 { "pm2fb", pm2fb_init, pm2fb_setup },
140 #endif
141 #ifdef CONFIG_FB_CLGEN
142 { "clgen", clgenfb_init, clgenfb_setup },
143 #endif
144 #ifdef CONFIG_FB_OF
145 { "offb", offb_init, offb_setup },
146 #endif
147 #ifdef CONFIG_FB_SBUS
148 { "sbus", sbusfb_init, sbusfb_setup },
149 #endif
150 #ifdef CONFIG_FB_ATY
151 { "atyfb", atyfb_init, atyfb_setup },
152 #endif
153 #ifdef CONFIG_FB_IGA
154 { "igafb", igafb_init, igafb_setup },
155 #endif
156 #ifdef CONFIG_FB_IMSTT
157 { "imsttfb", imsttfb_init, imsttfb_setup },
158 #endif
159 #ifdef CONFIG_APOLLO
160 { "apollo", dnfb_init, NULL },
161 #endif
162 #ifdef CONFIG_FB_Q40
163 { "q40fb", q40fb_init, NULL },
164 #endif
165 #ifdef CONFIG_FB_S3TRIO
166 { "s3trio", s3triofb_init, s3triofb_setup },
167 #endif
168 #ifdef CONFIG_FB_TGA
169 { "tga", tgafb_init, tgafb_setup },
170 #endif
171 #ifdef CONFIG_FB_VIRGE
172 { "virge", virgefb_init, virgefb_setup },
173 #endif
174 #ifdef CONFIG_FB_VESA
175 { "vesa", vesafb_init, vesafb_setup },
176 #endif
177 #ifdef CONFIG_FB_VGA16
178 { "vga16", vga16fb_init, vga16fb_setup },
179 #endif
180 #ifdef CONFIG_FB_MATROX
181 { "matrox", matroxfb_init, matroxfb_setup },
182 #endif
183 #ifdef CONFIG_FB_HP300
184 { "hpfb", hpfb_init, hpfb_setup },
185 #endif
186 #ifdef CONFIG_FB_CONTROL
187 { "controlfb", control_init, control_setup },
188 #endif
189 #ifdef CONFIG_FB_VALKYRIE
190 { "valkyriefb", valkyriefb_init, valkyriefb_setup },
191 #endif
192 #ifdef CONFIG_FB_G364
193 { "g364", g364fb_init, NULL },
194 #endif
195 #ifdef CONFIG_FB_FM2
196 { "fm2fb", fm2fb_init, fm2fb_setup },
197 #endif
198 #ifdef CONFIG_GSP_RESOLVER
199 /* Not a real frame buffer device... */
200 { "resolver", NULL, resolver_video_setup },
201 #endif
202 #ifdef CONFIG_FB_VIRTUAL
203 /* Must be last to avoid that vfb becomes your primary display */
204 { "vfb", vfb_init, vfb_setup },
205 #endif
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)
231 int fgc;
233 if (info->display_fg != NULL)
234 fgc = info->display_fg->vc_num;
235 else
236 return -1;
238 if (!current->tty)
239 return fgc;
241 if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
242 /* XXX Should report error here? */
243 return fgc;
245 if (MINOR(current->tty->device) < 1)
246 return fgc;
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)
254 struct fb_info **fi;
256 len = 0;
257 for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
258 if (*fi)
259 len += sprintf(buf + len, "%d %s\n",
260 GET_FB_IDX((*fi)->node),
261 (*fi)->modename);
262 *start = buf + offset;
263 return len > offset ? len - offset : 0;
266 static ssize_t
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;
275 char *base_addr;
276 ssize_t copy_size;
278 if (! fb || ! info->disp)
279 return -ENODEV;
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))
285 return -EFAULT;
286 *ppos += copy_size;
287 return copy_size;
290 static ssize_t
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;
299 char *base_addr;
300 ssize_t copy_size;
302 if (! fb || ! info->disp)
303 return -ENODEV;
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))
309 return -EFAULT;
310 file->f_pos += copy_size;
311 return copy_size;
315 static int set_all_vcs(int fbidx, struct fb_ops *fb,
316 struct fb_var_screeninfo *var, struct fb_info *info)
318 int unit, err;
320 var->activate |= FB_ACTIVATE_TEST;
321 err = fb->fb_set_var(var, PROC_CONSOLE(info), info);
322 var->activate &= ~FB_ACTIVATE_TEST;
323 if (err)
324 return err;
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);
328 return 0;
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;
336 char *fontdata;
337 unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog;
338 int userfont;
340 if (newidx != con2fb_map[unit]) {
341 oldfb = registered_fb[oldidx];
342 newfb = registered_fb[newidx];
343 if (newfb->fbops->fb_open(newfb,0))
344 return;
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);
371 #ifdef CONFIG_KMOD
372 static void try_to_load(int fb)
374 char modname[16];
376 sprintf(modname, "fb%d", fb);
377 request_module(modname);
379 #endif /* CONFIG_KMOD */
381 static int
382 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
383 unsigned long arg)
385 int fbidx = GET_FB_IDX(inode->i_rdev);
386 struct fb_info *info = registered_fb[fbidx];
387 struct fb_ops *fb = info->fbops;
388 struct fb_cmap cmap;
389 struct fb_var_screeninfo var;
390 struct fb_fix_screeninfo fix;
391 struct fb_con2fbmap con2fb;
392 int i;
394 if (! fb)
395 return -ENODEV;
396 switch (cmd) {
397 case FBIOGET_VSCREENINFO:
398 if ((i = fb->fb_get_var(&var, PROC_CONSOLE(info), info)))
399 return i;
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)))
404 return -EFAULT;
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);
408 if (i)
409 return i;
410 if (copy_to_user((void *) arg, &var, sizeof(var)))
411 return -EFAULT;
412 return 0;
413 case FBIOGET_FSCREENINFO:
414 if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(info), info)))
415 return i;
416 return copy_to_user((void *) arg, &fix, sizeof(fix)) ?
417 -EFAULT : 0;
418 case FBIOPUTCMAP:
419 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
420 return -EFAULT;
421 return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(info), info));
422 case FBIOGETCMAP:
423 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
424 return -EFAULT;
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)))
428 return -EFAULT;
429 if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(info), info)))
430 return i;
431 if (copy_to_user((void *) arg, &var, sizeof(var)))
432 return -EFAULT;
433 return i;
434 case FBIOGET_CON2FBMAP:
435 if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
436 return -EFAULT;
437 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
438 return -EINVAL;
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)))
444 return - EFAULT;
445 if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
446 return -EINVAL;
447 if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
448 return -EINVAL;
449 #ifdef CONFIG_KMOD
450 if (!registered_fb[con2fb.framebuffer])
451 try_to_load(con2fb.framebuffer);
452 #endif /* CONFIG_KMOD */
453 if (!registered_fb[con2fb.framebuffer])
454 return -EINVAL;
455 if (con2fb.console != 0)
456 set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
457 else
458 /* set them all */
459 for (i = 0; i < MAX_NR_CONSOLES; i++)
460 set_con2fb_map(i, con2fb.framebuffer);
461 return 0;
462 case FBIOBLANK:
463 if (info->blank == 0)
464 return -EINVAL;
465 (*info->blank)(arg, info);
466 return 0;
467 default:
468 return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
469 info);
473 static int
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;
481 unsigned long start;
482 u32 len;
484 if (!fb)
485 return -ENODEV;
486 if (fb->fb_mmap)
487 return fb->fb_mmap(info, file, vma);
489 #if defined(__sparc__)
490 /* Should never get here, all fb drivers should have their own
491 mmap routines */
492 return -EINVAL;
493 #else
494 /* non-SPARC... */
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;
501 start &= PAGE_MASK;
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);
507 if (var.accel_flags)
508 return -EINVAL;
509 start = fix.mmio_start;
510 len = (start & ~PAGE_MASK)+fix.mmio_len;
511 start &= PAGE_MASK;
512 len = (len+~PAGE_MASK) & PAGE_MASK;
514 if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
515 return -EINVAL;
516 vma->vm_offset += start;
517 if (vma->vm_offset & ~PAGE_MASK)
518 return -ENXIO;
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
540 * cached.
542 pgprot_val(vma->vm_page_prot) &= ~(PTE_CACHEABLE | PTE_BUFFERABLE);
543 #endif
544 #else
545 #warning What do we have to do here??
546 #endif
547 if (io_remap_page_range(vma->vm_start, vma->vm_offset,
548 vma->vm_end - vma->vm_start, vma->vm_page_prot))
549 return -EAGAIN;
550 return 0;
552 #endif /* defined(__sparc__) */
555 static int
556 fb_open(struct inode *inode, struct file *file)
558 int fbidx = GET_FB_IDX(inode->i_rdev);
559 struct fb_info *info;
561 #ifdef CONFIG_KMOD
562 if (!(info = registered_fb[fbidx]))
563 try_to_load(fbidx);
564 #endif /* CONFIG_KMOD */
565 if (!(info = registered_fb[fbidx]))
566 return -ENODEV;
567 return info->fbops->fb_open(info,1);
570 static int
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);
577 return 0;
580 static struct file_operations fb_fops = {
581 NULL, /* lseek */
582 fb_read, /* read */
583 fb_write, /* write */
584 NULL, /* readdir */
585 NULL, /* poll */
586 fb_ioctl, /* ioctl */
587 fb_mmap, /* mmap */
588 fb_open, /* open */
589 NULL, /* flush */
590 fb_release, /* release */
591 NULL /* fsync */
595 register_framebuffer(struct fb_info *fb_info)
597 int i, j;
598 static int fb_ever_opened[FB_MAX];
599 static int first = 1;
601 if (num_registered_fb == FB_MAX)
602 return -ENXIO;
603 num_registered_fb++;
604 for (i = 0 ; i < FB_MAX; i++)
605 if (!registered_fb[i])
606 break;
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
612 * many times
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;
620 if (first) {
621 first = 0;
622 take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
625 return 0;
629 unregister_framebuffer(const struct fb_info *fb_info)
631 int i, j;
633 i = GET_FB_IDX(fb_info->node);
634 for (j = 0; j < MAX_NR_CONSOLES; j++)
635 if (con2fb_map[j] == i)
636 return -EBUSY;
637 if (!registered_fb[i])
638 return -EINVAL;
639 registered_fb[i]=NULL;
640 num_registered_fb--;
641 return 0;
644 static struct proc_dir_entry *proc_fbmem;
646 void __init
647 fbmem_init(void)
649 int i;
651 proc_fbmem = create_proc_entry("fb", 0, 0);
652 if (proc_fbmem)
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)
673 #if 0
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;
683 if (!vpicos)
684 return 0;
686 if (monspecs->hfmin == 0)
687 return 1;
689 if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 ||
690 vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12)
691 return 0;
692 #endif
693 return 1;
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)
708 int i, j;
710 if (!options || !*options)
711 return 0;
713 if (!strncmp(options, "scrollback:", 11)) {
714 options += 11;
715 if (*options) {
716 fbcon_softback_size = simple_strtoul(options, &options, 0);
717 if (*options == 'k' || *options == 'K') {
718 fbcon_softback_size *= 1024;
719 options++;
721 if (*options != ',')
722 return 0;
723 options++;
724 } else
725 return 0;
728 if (!strncmp(options, "map:", 4)) {
729 options += 4;
730 if (*options)
731 for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
732 if (!options[j])
733 j = 0;
734 con2fb_map[i] = (options[j++]-'0') % FB_MAX;
736 return 0;
739 if (!strncmp(options, "vc:", 3)) {
740 options += 3;
741 if (*options)
742 first_fb_vc = simple_strtoul(options, &options, 10) - 1;
743 if (first_fb_vc < 0)
744 first_fb_vc = 0;
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)
751 return 0;
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) &&
756 options[j] == ':') {
757 if (!strcmp(options+j+1, "off"))
758 fb_drivers[i].init = NULL;
759 else {
760 if (fb_drivers[i].init) {
761 pref_init_funcs[num_pref_init_funcs++] =
762 fb_drivers[i].init;
763 fb_drivers[i].init = NULL;
765 if (fb_drivers[i].setup)
766 fb_drivers[i].setup(options+j+1);
768 return 0;
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;
777 return 0;
780 __setup("video=", video_setup);
783 * Visible symbols for modules
786 EXPORT_SYMBOL(register_framebuffer);
787 EXPORT_SYMBOL(unregister_framebuffer);