Import 2.4.0-test6pre4
[davej-history.git] / drivers / video / fbmem.c
blob6ca8c3dcfea8f236c171dfc871de4805509f7030
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/smp_lock.h>
18 #include <linux/kernel.h>
19 #include <linux/major.h>
20 #include <linux/malloc.h>
21 #include <linux/mman.h>
22 #include <linux/tty.h>
23 #include <linux/console.h>
24 #include <linux/init.h>
25 #include <linux/proc_fs.h>
26 #ifdef CONFIG_KMOD
27 #include <linux/kmod.h>
28 #endif
29 #include <linux/devfs_fs_kernel.h>
31 #if defined(__mc68000__) || defined(CONFIG_APUS)
32 #include <asm/setup.h>
33 #endif
35 #include <asm/io.h>
36 #include <asm/uaccess.h>
37 #include <asm/page.h>
38 #include <asm/pgtable.h>
40 #include <linux/fb.h>
41 #include <video/fbcon.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 hitfb_init(void);
66 extern int hitfb_setup(char*);
67 extern int vfb_init(void);
68 extern int vfb_setup(char*);
69 extern int offb_init(void);
70 extern int atyfb_init(void);
71 extern int atyfb_setup(char*);
72 extern int aty128fb_init(void);
73 extern int aty128fb_setup(char*);
74 extern int igafb_init(void);
75 extern int igafb_setup(char*);
76 extern int imsttfb_init(void);
77 extern int imsttfb_setup(char*);
78 extern int dnfb_init(void);
79 extern int tgafb_init(void);
80 extern int tgafb_setup(char*);
81 extern int virgefb_init(void);
82 extern int virgefb_setup(char*);
83 extern int resolver_video_setup(char*);
84 extern int s3triofb_init(void);
85 extern int vesafb_init(void);
86 extern int vesafb_setup(char*);
87 extern int vga16fb_init(void);
88 extern int vga16fb_setup(char*);
89 extern int hgafb_init(void);
90 extern int hgafb_setup(char*);
91 extern int matroxfb_init(void);
92 extern int matroxfb_setup(char*);
93 extern int hpfb_init(void);
94 extern int hpfb_setup(char*);
95 extern int sbusfb_init(void);
96 extern int sbusfb_setup(char*);
97 extern int control_init(void);
98 extern int control_setup(char*);
99 extern int platinum_init(void);
100 extern int platinum_setup(char*);
101 extern int valkyriefb_init(void);
102 extern int valkyriefb_setup(char*);
103 extern int chips_init(void);
104 extern int g364fb_init(void);
105 extern int sa1100fb_init(void);
106 extern int sa1100fb_setup(char*);
107 extern int fm2fb_init(void);
108 extern int fm2fb_setup(char*);
109 extern int q40fb_init(void);
110 extern int sun3fb_init(void);
111 extern int sun3fb_setup(char *);
112 extern int sgivwfb_init(void);
113 extern int sgivwfb_setup(char*);
114 extern int rivafb_init(void);
115 extern int rivafb_setup(char*);
116 extern int tdfxfb_init(void);
117 extern int tdfxfb_setup(char*);
118 extern int sisfb_init(void);
119 extern int sisfb_setup(char*);
121 static struct {
122 const char *name;
123 int (*init)(void);
124 int (*setup)(char*);
125 } fb_drivers[] __initdata = {
127 #ifdef CONFIG_FB_SBUS
129 * Sbusfb must be initialized _before_ other frame buffer devices that
130 * use PCI probing
132 { "sbus", sbusfb_init, sbusfb_setup },
133 #endif
136 * Chipset specific drivers that use resource management
139 #ifdef CONFIG_FB_RETINAZ3
140 { "retz3", retz3fb_init, retz3fb_setup },
141 #endif
142 #ifdef CONFIG_FB_AMIGA
143 { "amifb", amifb_init, amifb_setup },
144 #endif
145 #ifdef CONFIG_FB_CYBER
146 { "cyber", cyberfb_init, cyberfb_setup },
147 #endif
148 #ifdef CONFIG_FB_CYBER2000
149 { "cyber2000", cyber2000fb_init, cyber2000fb_setup },
150 #endif
151 #ifdef CONFIG_FB_PM2
152 { "pm2fb", pm2fb_init, pm2fb_setup },
153 #endif
154 #ifdef CONFIG_FB_CLGEN
155 { "clgen", clgenfb_init, clgenfb_setup },
156 #endif
157 #ifdef CONFIG_FB_ATY
158 { "atyfb", atyfb_init, atyfb_setup },
159 #endif
160 #ifdef CONFIG_FB_MATROX
161 { "matrox", matroxfb_init, matroxfb_setup },
162 #endif
163 #ifdef CONFIG_FB_ATY128
164 { "aty128fb", aty128fb_init, aty128fb_setup },
165 #endif
166 #ifdef CONFIG_FB_VIRGE
167 { "virge", virgefb_init, virgefb_setup },
168 #endif
169 #ifdef CONFIG_FB_RIVA
170 { "riva", rivafb_init, rivafb_setup },
171 #endif
172 #ifdef CONFIG_FB_CONTROL
173 { "controlfb", control_init, control_setup },
174 #endif
175 #ifdef CONFIG_FB_PLATINUM
176 { "platinumfb", platinum_init, platinum_setup },
177 #endif
178 #ifdef CONFIG_FB_VALKYRIE
179 { "valkyriefb", valkyriefb_init, valkyriefb_setup },
180 #endif
181 #ifdef CONFIG_FB_CT65550
182 { "chipsfb", chips_init, NULL },
183 #endif
184 #ifdef CONFIG_FB_IMSTT
185 { "imsttfb", imsttfb_init, imsttfb_setup },
186 #endif
187 #ifdef CONFIG_FB_S3TRIO
188 { "s3trio", s3triofb_init, NULL },
189 #endif
190 #ifdef CONFIG_FB_FM2
191 { "fm2fb", fm2fb_init, fm2fb_setup },
192 #endif
193 #ifdef CONFIG_FB_SIS
194 { "sisfb", sisfb_init, sisfb_setup },
195 #endif
198 * Generic drivers that are used as fallbacks
200 * These depend on resource management and must be initialized
201 * _after_ all other frame buffer devices that use resource
202 * management!
205 #ifdef CONFIG_FB_OF
206 { "offb", offb_init, NULL },
207 #endif
208 #ifdef CONFIG_FB_VESA
209 { "vesa", vesafb_init, vesafb_setup },
210 #endif
213 * Chipset specific drivers that don't use resource management (yet)
216 #ifdef CONFIG_FB_3DFX
217 { "tdfx", tdfxfb_init, tdfxfb_setup },
218 #endif
219 #ifdef CONFIG_FB_SGIVW
220 { "sgivw", sgivwfb_init, sgivwfb_setup },
221 #endif
222 #ifdef CONFIG_FB_ACORN
223 { "acorn", acornfb_init, acornfb_setup },
224 #endif
225 #ifdef CONFIG_FB_ATARI
226 { "atafb", atafb_init, atafb_setup },
227 #endif
228 #ifdef CONFIG_FB_MAC
229 { "macfb", macfb_init, macfb_setup },
230 #endif
231 #ifdef CONFIG_FB_HGA
232 { "hga", hgafb_init, hgafb_setup },
233 #endif
234 #ifdef CONFIG_FB_IGA
235 { "igafb", igafb_init, igafb_setup },
236 #endif
237 #ifdef CONFIG_APOLLO
238 { "apollo", dnfb_init, NULL },
239 #endif
240 #ifdef CONFIG_FB_Q40
241 { "q40fb", q40fb_init, NULL },
242 #endif
243 #ifdef CONFIG_FB_TGA
244 { "tga", tgafb_init, tgafb_setup },
245 #endif
246 #ifdef CONFIG_FB_HP300
247 { "hpfb", hpfb_init, hpfb_setup },
248 #endif
249 #ifdef CONFIG_FB_G364
250 { "g364", g364fb_init, NULL },
251 #endif
252 #ifdef CONFIG_FB_SA1100
253 { "sa1100", sa1100fb_init, sa1100fb_setup },
254 #endif
255 #ifdef CONFIG_FB_SUN3
256 { "sun3", sun3fb_init, sun3fb_setup },
257 #endif
258 #ifdef CONFIG_FB_HIT
259 { "hitfb", hitfb_init, hitfb_setup },
260 #endif
263 * Generic drivers that don't use resource management (yet)
266 #ifdef CONFIG_FB_VGA16
267 { "vga16", vga16fb_init, vga16fb_setup },
268 #endif
270 #ifdef CONFIG_GSP_RESOLVER
271 /* Not a real frame buffer device... */
272 { "resolver", NULL, resolver_video_setup },
273 #endif
275 #ifdef CONFIG_FB_VIRTUAL
277 * Vfb must be last to avoid that it becomes your primary display if
278 * other display devices are present
280 { "vfb", vfb_init, vfb_setup },
281 #endif
284 #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
286 extern const char *global_mode_option;
288 static initcall_t pref_init_funcs[FB_MAX];
289 static int num_pref_init_funcs __initdata = 0;
292 struct fb_info *registered_fb[FB_MAX];
293 int num_registered_fb = 0;
294 extern int fbcon_softback_size;
296 static int first_fb_vc = 0;
297 static int last_fb_vc = MAX_NR_CONSOLES-1;
298 static int fbcon_is_default = 1;
300 #ifdef CONFIG_FB_OF
301 static int ofonly __initdata = 0;
302 #endif
304 static int fbmem_read_proc(char *buf, char **start, off_t offset,
305 int len, int *eof, void *private)
307 struct fb_info **fi;
308 int clen;
310 clen = 0;
311 for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
312 if (*fi)
313 clen += sprintf(buf + clen, "%d %s\n",
314 GET_FB_IDX((*fi)->node),
315 (*fi)->modename);
316 *start = buf + offset;
317 if (clen > offset)
318 clen -= offset;
319 else
320 clen = 0;
321 return clen < len ? clen : len;
324 static ssize_t
325 fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
327 unsigned long p = *ppos;
328 struct inode *inode = file->f_dentry->d_inode;
329 int fbidx = GET_FB_IDX(inode->i_rdev);
330 struct fb_info *info = registered_fb[fbidx];
331 struct fb_ops *fb = info->fbops;
332 struct fb_fix_screeninfo fix;
334 if (! fb || ! info->disp)
335 return -ENODEV;
337 fb->fb_get_fix(&fix,PROC_CONSOLE(info), info);
338 if (p >= fix.smem_len)
339 return 0;
340 if (count >= fix.smem_len)
341 count = fix.smem_len;
342 if (count + p > fix.smem_len)
343 count = fix.smem_len - p;
344 if (count) {
345 char *base_addr;
347 base_addr = info->disp->screen_base;
348 count -= copy_to_user(buf, base_addr+p, count);
349 if (!count)
350 return -EFAULT;
351 *ppos += count;
353 return count;
356 static ssize_t
357 fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
359 unsigned long p = *ppos;
360 struct inode *inode = file->f_dentry->d_inode;
361 int fbidx = GET_FB_IDX(inode->i_rdev);
362 struct fb_info *info = registered_fb[fbidx];
363 struct fb_ops *fb = info->fbops;
364 struct fb_fix_screeninfo fix;
365 int err;
367 if (! fb || ! info->disp)
368 return -ENODEV;
370 fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
371 if (p > fix.smem_len)
372 return -ENOSPC;
373 if (count >= fix.smem_len)
374 count = fix.smem_len;
375 err = 0;
376 if (count + p > fix.smem_len) {
377 count = fix.smem_len - p;
378 err = -ENOSPC;
380 if (count) {
381 char *base_addr;
383 base_addr = info->disp->screen_base;
384 count -= copy_from_user(base_addr+p, buf, count);
385 *ppos += count;
386 err = -EFAULT;
388 if (count)
389 return count;
390 return err;
393 #ifdef CONFIG_KMOD
394 static void try_to_load(int fb)
396 char modname[16];
398 sprintf(modname, "fb%d", fb);
399 request_module(modname);
401 #endif /* CONFIG_KMOD */
403 static int
404 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
405 unsigned long arg)
407 int fbidx = GET_FB_IDX(inode->i_rdev);
408 struct fb_info *info = registered_fb[fbidx];
409 struct fb_ops *fb = info->fbops;
410 struct fb_cmap cmap;
411 struct fb_var_screeninfo var;
412 struct fb_fix_screeninfo fix;
413 struct fb_con2fbmap con2fb;
414 int i;
416 if (! fb)
417 return -ENODEV;
418 switch (cmd) {
419 case FBIOGET_VSCREENINFO:
420 if ((i = fb->fb_get_var(&var, PROC_CONSOLE(info), info)))
421 return i;
422 return copy_to_user((void *) arg, &var,
423 sizeof(var)) ? -EFAULT : 0;
424 case FBIOPUT_VSCREENINFO:
425 if (copy_from_user(&var, (void *) arg, sizeof(var)))
426 return -EFAULT;
427 i = var.activate & FB_ACTIVATE_ALL
428 ? set_all_vcs(fbidx, fb, &var, info)
429 : fb->fb_set_var(&var, PROC_CONSOLE(info), info);
430 if (i)
431 return i;
432 if (copy_to_user((void *) arg, &var, sizeof(var)))
433 return -EFAULT;
434 return 0;
435 case FBIOGET_FSCREENINFO:
436 if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(info), info)))
437 return i;
438 return copy_to_user((void *) arg, &fix, sizeof(fix)) ?
439 -EFAULT : 0;
440 case FBIOPUTCMAP:
441 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
442 return -EFAULT;
443 return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(info), info));
444 case FBIOGETCMAP:
445 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
446 return -EFAULT;
447 return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE(info), info));
448 case FBIOPAN_DISPLAY:
449 if (copy_from_user(&var, (void *) arg, sizeof(var)))
450 return -EFAULT;
451 if (fb->fb_pan_display == NULL)
452 return (var.xoffset || var.yoffset) ? -EINVAL : 0;
453 if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(info), info)))
454 return i;
455 if (copy_to_user((void *) arg, &var, sizeof(var)))
456 return -EFAULT;
457 return i;
458 case FBIOGET_CON2FBMAP:
459 if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
460 return -EFAULT;
461 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
462 return -EINVAL;
463 con2fb.framebuffer = con2fb_map[con2fb.console-1];
464 return copy_to_user((void *)arg, &con2fb,
465 sizeof(con2fb)) ? -EFAULT : 0;
466 case FBIOPUT_CON2FBMAP:
467 if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
468 return - EFAULT;
469 if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
470 return -EINVAL;
471 if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
472 return -EINVAL;
473 #ifdef CONFIG_KMOD
474 if (!registered_fb[con2fb.framebuffer])
475 try_to_load(con2fb.framebuffer);
476 #endif /* CONFIG_KMOD */
477 if (!registered_fb[con2fb.framebuffer])
478 return -EINVAL;
479 if (con2fb.console != 0)
480 set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
481 else
482 /* set them all */
483 for (i = 0; i < MAX_NR_CONSOLES; i++)
484 set_con2fb_map(i, con2fb.framebuffer);
485 return 0;
486 case FBIOBLANK:
487 if (info->blank == 0)
488 return -EINVAL;
489 (*info->blank)(arg, info);
490 return 0;
491 default:
492 if (fb->fb_ioctl == NULL)
493 return -EINVAL;
494 return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
495 info);
499 static int
500 fb_mmap(struct file *file, struct vm_area_struct * vma)
502 int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev);
503 struct fb_info *info = registered_fb[fbidx];
504 struct fb_ops *fb = info->fbops;
505 unsigned long off;
506 #if !defined(__sparc__) || defined(__sparc_v9__)
507 struct fb_fix_screeninfo fix;
508 struct fb_var_screeninfo var;
509 unsigned long start;
510 u32 len;
511 #endif
513 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
514 return -EINVAL;
515 off = vma->vm_pgoff << PAGE_SHIFT;
516 if (!fb)
517 return -ENODEV;
518 if (fb->fb_mmap) {
519 int res;
520 lock_kernel();
521 res = fb->fb_mmap(info, file, vma);
522 unlock_kernel();
523 return res;
526 #if defined(__sparc__) && !defined(__sparc_v9__)
527 /* Should never get here, all fb drivers should have their own
528 mmap routines */
529 return -EINVAL;
530 #else
531 /* !sparc32... */
533 lock_kernel();
534 fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
536 /* frame buffer memory */
537 start = fix.smem_start;
538 len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len);
539 if (off >= len) {
540 /* memory mapped io */
541 off -= len;
542 fb->fb_get_var(&var, PROC_CONSOLE(info), info);
543 if (var.accel_flags)
544 return -EINVAL;
545 start = fix.mmio_start;
546 len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len);
548 unlock_kernel();
549 start &= PAGE_MASK;
550 if ((vma->vm_end - vma->vm_start + off) > len)
551 return -EINVAL;
552 off += start;
553 vma->vm_pgoff = off >> PAGE_SHIFT;
554 #if defined(__sparc_v9__)
555 vma->vm_flags |= (VM_SHM | VM_LOCKED);
557 unsigned long align, j;
558 for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
559 if (len >= align && !((start & ~PAGE_MASK) & (align - 1)))
560 break;
561 if (align > PAGE_SIZE && vma->vm_start & (align - 1)) {
562 /* align as much as possible */
563 struct vm_area_struct *vmm;
564 j = (-vma->vm_start) & (align - 1);
565 vmm = find_vma(current->mm, vma->vm_start);
566 if (!vmm || vmm->vm_start >= vma->vm_end + j) {
567 vma->vm_start += j;
568 vma->vm_end += j;
572 if (io_remap_page_range(vma->vm_start, off,
573 vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
574 return -EAGAIN;
575 vma->vm_flags |= VM_IO;
576 #else
577 #if defined(__mc68000__)
578 #if defined(CONFIG_SUN3)
579 pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
580 #else
581 if (CPU_IS_020_OR_030)
582 pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
583 if (CPU_IS_040_OR_060) {
584 pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
585 /* Use no-cache mode, serialized */
586 pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
588 #endif
589 #elif defined(__powerpc__)
590 pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
591 #elif defined(__alpha__)
592 /* Caching is off in the I/O space quadrant by design. */
593 #elif defined(__i386__)
594 if (boot_cpu_data.x86 > 3)
595 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
596 #elif defined(__mips__)
597 pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
598 pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
599 #elif defined(__arm__)
600 #if defined(CONFIG_CPU_32) && !defined(CONFIG_ARCH_ACORN)
601 /* On Acorn architectures, we want to keep the framebuffer
602 * cached.
604 pgprot_val(vma->vm_page_prot) &= ~(PTE_CACHEABLE | PTE_BUFFERABLE);
605 #endif
606 #elif defined(__sh__)
607 pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
608 #else
609 #warning What do we have to do here??
610 #endif
611 if (io_remap_page_range(vma->vm_start, off,
612 vma->vm_end - vma->vm_start, vma->vm_page_prot))
613 return -EAGAIN;
614 #endif /* !__sparc_v9__ */
615 return 0;
616 #endif /* !sparc32 */
619 #if 1 /* to go away in 2.5.0 */
620 int GET_FB_IDX(kdev_t rdev)
622 int fbidx = MINOR(rdev);
623 if (fbidx >= 32) {
624 int newfbidx = fbidx >> 5;
625 static int warned = 0;
626 if (!(warned & (1<<newfbidx))) {
627 warned |= 1<<newfbidx;
628 printk("Warning: Remapping obsolete /dev/fb* minor %d to %d\n",
629 fbidx, newfbidx);
631 fbidx = newfbidx;
633 return fbidx;
635 #endif
637 static int
638 fb_open(struct inode *inode, struct file *file)
640 int fbidx = GET_FB_IDX(inode->i_rdev);
641 struct fb_info *info;
642 int res = 0;
644 #ifdef CONFIG_KMOD
645 if (!(info = registered_fb[fbidx]))
646 try_to_load(fbidx);
647 #endif /* CONFIG_KMOD */
648 if (!(info = registered_fb[fbidx]))
649 return -ENODEV;
650 if (info->fbops->owner)
651 __MOD_INC_USE_COUNT(info->fbops->owner);
652 if (info->fbops->fb_open) {
653 res = info->fbops->fb_open(info,1);
654 if (res && info->fbops->owner)
655 __MOD_DEC_USE_COUNT(info->fbops->owner);
657 return res;
660 static int
661 fb_release(struct inode *inode, struct file *file)
663 int fbidx = GET_FB_IDX(inode->i_rdev);
664 struct fb_info *info;
666 lock_kernel();
667 info = registered_fb[fbidx];
668 if (info->fbops->fb_release)
669 info->fbops->fb_release(info,1);
670 if (info->fbops->owner)
671 __MOD_DEC_USE_COUNT(info->fbops->owner);
672 unlock_kernel();
673 return 0;
676 static struct file_operations fb_fops = {
677 owner: THIS_MODULE,
678 read: fb_read,
679 write: fb_write,
680 ioctl: fb_ioctl,
681 mmap: fb_mmap,
682 open: fb_open,
683 release: fb_release,
686 static devfs_handle_t devfs_handle = NULL;
689 register_framebuffer(struct fb_info *fb_info)
691 int i, j;
692 char name_buf[8];
693 static int fb_ever_opened[FB_MAX];
694 static int first = 1;
696 if (num_registered_fb == FB_MAX)
697 return -ENXIO;
698 num_registered_fb++;
699 for (i = 0 ; i < FB_MAX; i++)
700 if (!registered_fb[i])
701 break;
702 fb_info->node = MKDEV(FB_MAJOR, i);
703 registered_fb[i] = fb_info;
704 if (!fb_ever_opened[i]) {
705 struct module *owner = fb_info->fbops->owner;
707 * We assume initial frame buffer devices can be opened this
708 * many times
710 for (j = 0; j < MAX_NR_CONSOLES; j++)
711 if (con2fb_map[j] == i) {
712 if (owner)
713 __MOD_INC_USE_COUNT(owner);
714 if (!fb_info->fbops->fb_open)
715 continue;
716 if (!fb_info->fbops->fb_open(fb_info,0))
717 continue;
718 if (owner)
719 __MOD_DEC_USE_COUNT(owner);
721 fb_ever_opened[i] = 1;
724 if (first) {
725 first = 0;
726 take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
728 sprintf (name_buf, "%d", i);
729 fb_info->devfs_handle =
730 devfs_register (devfs_handle, name_buf, DEVFS_FL_DEFAULT,
731 FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO,
732 &fb_fops, NULL);
734 return 0;
738 unregister_framebuffer(struct fb_info *fb_info)
740 int i, j;
742 i = GET_FB_IDX(fb_info->node);
743 for (j = 0; j < MAX_NR_CONSOLES; j++)
744 if (con2fb_map[j] == i)
745 return -EBUSY;
746 if (!registered_fb[i])
747 return -EINVAL;
748 devfs_unregister (fb_info->devfs_handle);
749 fb_info->devfs_handle = NULL;
750 devfs_unregister (fb_info->devfs_lhandle);
751 fb_info->devfs_lhandle = NULL;
752 registered_fb[i]=NULL;
753 num_registered_fb--;
754 return 0;
757 void __init
758 fbmem_init(void)
760 int i;
762 create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
764 devfs_handle = devfs_mk_dir (NULL, "fb", NULL);
765 if (devfs_register_chrdev(FB_MAJOR,"fb",&fb_fops))
766 printk("unable to get major %d for fb devs\n", FB_MAJOR);
768 #ifdef CONFIG_FB_OF
769 if (ofonly) {
770 offb_init();
771 return;
773 #endif
776 * Probe for all builtin frame buffer devices
778 for (i = 0; i < num_pref_init_funcs; i++)
779 pref_init_funcs[i]();
781 for (i = 0; i < NUM_FB_DRIVERS; i++)
782 if (fb_drivers[i].init)
783 fb_drivers[i].init();
787 * Command line options
790 int __init video_setup(char *options)
792 int i, j;
794 if (!options || !*options)
795 return 0;
797 if (!strncmp(options, "scrollback:", 11)) {
798 options += 11;
799 if (*options) {
800 fbcon_softback_size = simple_strtoul(options, &options, 0);
801 if (*options == 'k' || *options == 'K') {
802 fbcon_softback_size *= 1024;
803 options++;
805 if (*options != ',')
806 return 0;
807 options++;
808 } else
809 return 0;
812 if (!strncmp(options, "map:", 4)) {
813 options += 4;
814 if (*options)
815 for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
816 if (!options[j])
817 j = 0;
818 con2fb_map[i] = (options[j++]-'0') % FB_MAX;
820 return 0;
823 if (!strncmp(options, "vc:", 3)) {
824 options += 3;
825 if (*options)
826 first_fb_vc = simple_strtoul(options, &options, 10) - 1;
827 if (first_fb_vc < 0)
828 first_fb_vc = 0;
829 if (*options++ == '-')
830 last_fb_vc = simple_strtoul(options, &options, 10) - 1;
831 fbcon_is_default = 0;
834 #ifdef CONFIG_FB_OF
835 if (!strcmp(options, "ofonly")) {
836 ofonly = 1;
837 return 0;
839 #endif
841 if (num_pref_init_funcs == FB_MAX)
842 return 0;
844 for (i = 0; i < NUM_FB_DRIVERS; i++) {
845 j = strlen(fb_drivers[i].name);
846 if (!strncmp(options, fb_drivers[i].name, j) &&
847 options[j] == ':') {
848 if (!strcmp(options+j+1, "off"))
849 fb_drivers[i].init = NULL;
850 else {
851 if (fb_drivers[i].init) {
852 pref_init_funcs[num_pref_init_funcs++] =
853 fb_drivers[i].init;
854 fb_drivers[i].init = NULL;
856 if (fb_drivers[i].setup)
857 fb_drivers[i].setup(options+j+1);
859 return 0;
864 * If we get here no fb was specified.
865 * We consider the argument to be a global video mode option.
867 global_mode_option = options;
868 return 0;
871 __setup("video=", video_setup);
874 * Visible symbols for modules
877 EXPORT_SYMBOL(register_framebuffer);
878 EXPORT_SYMBOL(unregister_framebuffer);
879 EXPORT_SYMBOL(registered_fb);
880 EXPORT_SYMBOL(num_registered_fb);
881 #if 1 /* to go away in 2.5.0 */
882 EXPORT_SYMBOL(GET_FB_IDX);
883 #endif