Import 2.1.118
[davej-history.git] / drivers / char / fbmem.c
blobe1c11404043dd73596aaccee338105e83f27e684
1 /*
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
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 #ifdef CONFIG_PROC_FS
26 #include <linux/proc_fs.h>
27 #endif
28 #ifdef CONFIG_KMOD
29 #include <linux/kmod.h>
30 #endif
32 #ifdef __mc68000__
33 #include <asm/setup.h>
34 #endif
35 #ifdef __powerpc__
36 #include <asm/io.h>
37 #endif
38 #include <asm/uaccess.h>
39 #include <asm/page.h>
40 #include <asm/pgtable.h>
42 #include <linux/fb.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);
87 static struct {
88 const char *name;
89 void (*init)(void);
90 void (*setup)(char *options, int *ints);
91 } fb_drivers[] __initdata = {
92 #ifdef CONFIG_FB_RETINAZ3
93 { "retz3", retz3fb_init, retz3fb_setup },
94 #endif
95 #ifdef CONFIG_FB_ACORN
96 { "acorn", acornfb_init, acornfb_setup },
97 #endif
98 #ifdef CONFIG_FB_AMIGA
99 { "amifb", amifb_init, amifb_setup },
100 #endif
101 #ifdef CONFIG_FB_ATARI
102 { "atafb", atafb_init, atafb_setup },
103 #endif
104 #ifdef CONFIG_FB_MAC
105 { "macfb", macfb_init, macfb_setup },
106 #endif
107 #ifdef CONFIG_FB_CYBER
108 { "cyber", cyberfb_init, cyberfb_setup },
109 #endif
110 #ifdef CONFIG_FB_CLGEN
111 { "clgen", clgenfb_init, clgenfb_setup },
112 #endif
113 #ifdef CONFIG_FB_OF
114 { "offb", offb_init, offb_setup },
115 #endif
116 #ifdef CONFIG_FB_ATY
117 { "atyfb", atyfb_init, atyfb_setup },
118 #endif
119 #ifdef CONFIG_APOLLO
120 { "apollo", dnfb_init, NULL },
121 #endif
122 #ifdef CONFIG_FB_S3TRIO
123 { "s3trio", s3triofb_init, s3triofb_setup },
124 #endif
125 #ifdef CONFIG_FB_TGA
126 { "tga", tgafb_init, NULL },
127 #endif
128 #ifdef CONFIG_FB_VIRGE
129 { "virge", virgefb_init, virgefb_setup },
130 #endif
131 #ifdef CONFIG_FB_VGA
132 { "vga", vgafb_init, vgafb_setup },
133 #endif
134 #ifdef CONFIG_FB_VESA
135 { "vesa", vesafb_init, vesafb_setup },
136 #endif
137 #ifdef CONFIG_FB_MDA
138 { "mda", mdafb_init, mdafb_setup },
139 #endif
140 #ifdef CONFIG_FB_HP300
141 { "hpfb", hpfb_init, hpfb_setup },
142 #endif
143 #ifdef CONFIG_FB_SBUS
144 { "sbus", sbusfb_init, sbusfb_setup },
145 #endif
146 #ifdef CONFIG_GSP_RESOLVER
147 /* Not a real frame buffer device... */
148 { "resolver", NULL, resolver_video_setup },
149 #endif
150 #ifdef CONFIG_FB_VIRTUAL
151 /* Must be last to avoid that vfb becomes your primary display */
152 { "vfb", vfb_init, vfb_setup },
153 #endif
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)
172 if (!current->tty)
173 return fg_console;
175 if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
176 /* XXX Should report error here? */
177 return fg_console;
179 if (MINOR(current->tty->device) < 1)
180 return fg_console;
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)
189 struct fb_info **fi;
191 len = 0;
192 for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
193 if (*fi)
194 len += sprintf(buf + len, "%d %s\n",
195 GET_FB_IDX((*fi)->node),
196 (*fi)->modename);
197 *start = buf + offset;
198 return len > offset ? len - offset : 0;
200 #endif
202 static ssize_t
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;
211 char *base_addr;
212 ssize_t copy_size;
214 if (! fb || ! info->disp)
215 return -ENODEV;
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))
221 return -EFAULT;
222 *ppos += copy_size;
223 return copy_size;
226 static ssize_t
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;
235 char *base_addr;
236 ssize_t copy_size;
238 if (! fb || ! info->disp)
239 return -ENODEV;
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))
245 return -EFAULT;
246 file->f_pos += copy_size;
247 return 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))
261 return;
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);
276 #ifdef CONFIG_KMOD
277 static void try_to_load(int fb)
279 char modname[16];
281 sprintf(modname, "fb%d", fb);
282 request_module(modname);
284 #endif /* CONFIG_KMOD */
286 static int
287 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
288 unsigned long arg)
290 int fbidx = GET_FB_IDX(inode->i_rdev);
291 struct fb_info *info = registered_fb[fbidx];
292 struct fb_ops *fb = info->fbops;
293 struct fb_cmap cmap;
294 struct fb_var_screeninfo var;
295 struct fb_fix_screeninfo fix;
296 struct fb_con2fbmap con2fb;
297 int i;
299 if (! fb)
300 return -ENODEV;
301 switch (cmd) {
302 case FBIOGET_VSCREENINFO:
303 if ((i = fb->fb_get_var(&var, PROC_CONSOLE(), info)))
304 return i;
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)))
309 return -EFAULT;
310 if ((i = fb->fb_set_var(&var, PROC_CONSOLE(), info)))
311 return i;
312 if (copy_to_user((void *) arg, &var, sizeof(var)))
313 return -EFAULT;
314 return 0;
315 case FBIOGET_FSCREENINFO:
316 if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(), info)))
317 return i;
318 return copy_to_user((void *) arg, &fix, sizeof(fix)) ?
319 -EFAULT : 0;
320 case FBIOPUTCMAP:
321 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
322 return -EFAULT;
323 return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(), info));
324 case FBIOGETCMAP:
325 if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
326 return -EFAULT;
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)))
330 return -EFAULT;
331 if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(), info)))
332 return i;
333 if (copy_to_user((void *) arg, &var, sizeof(var)))
334 return -EFAULT;
335 return i;
336 case FBIOGET_CON2FBMAP:
337 if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
338 return -EFAULT;
339 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
340 return -EINVAL;
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)))
346 return - EFAULT;
347 if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
348 return -EINVAL;
349 if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
350 return -EINVAL;
351 #ifdef CONFIG_KMOD
352 if (!registered_fb[con2fb.framebuffer])
353 try_to_load(con2fb.framebuffer);
354 #endif /* CONFIG_KMOD */
355 if (!registered_fb[con2fb.framebuffer])
356 return -EINVAL;
357 if (con2fb.console != 0)
358 set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
359 else
360 /* set them all */
361 for (i = 0; i < MAX_NR_CONSOLES; i++)
362 set_con2fb_map(i, con2fb.framebuffer);
363 return 0;
364 default:
365 return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(),
366 info);
370 static int
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;
378 unsigned long start;
379 u32 len;
381 if (!fb)
382 return -ENODEV;
383 if (fb->fb_mmap)
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;
390 start &= PAGE_MASK;
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);
396 if (var.accel_flags)
397 return -EINVAL;
398 start = (unsigned long)fix.mmio_start;
399 len = (start & ~PAGE_MASK)+fix.mmio_len;
400 start &= PAGE_MASK;
401 len = (len+~PAGE_MASK) & PAGE_MASK;
403 if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
404 return -EINVAL;
405 vma->vm_offset += start;
406 if (vma->vm_offset & ~PAGE_MASK)
407 return -ENXIO;
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
422 mmap routines */
423 #elif defined(__i386__)
424 if (boot_cpu_data.x86 > 3)
425 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
426 #else
427 #warning What do we have to do here??
428 #endif
429 if (remap_page_range(vma->vm_start, vma->vm_offset,
430 vma->vm_end - vma->vm_start, vma->vm_page_prot))
431 return -EAGAIN;
432 vma->vm_file = file;
433 file->f_count++;
434 return 0;
437 static int
438 fb_open(struct inode *inode, struct file *file)
440 int fbidx = GET_FB_IDX(inode->i_rdev);
441 struct fb_info *info;
443 #ifdef CONFIG_KMOD
444 if (!(info = registered_fb[fbidx]))
445 try_to_load(fbidx);
446 #endif /* CONFIG_KMOD */
447 if (!(info = registered_fb[fbidx]))
448 return -ENODEV;
449 return info->fbops->fb_open(info,1);
452 static int
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);
459 return 0;
462 static struct file_operations fb_fops = {
463 NULL, /* lseek */
464 fb_read, /* read */
465 fb_write, /* write */
466 NULL, /* readdir */
467 NULL, /* poll */
468 fb_ioctl, /* ioctl */
469 fb_mmap, /* mmap */
470 fb_open, /* open */
471 NULL, /* flush */
472 fb_release, /* release */
473 NULL /* fsync */
477 register_framebuffer(struct fb_info *fb_info)
479 int i, j;
480 static int fb_ever_opened[FB_MAX];
481 static int first = 1;
483 if (num_registered_fb == FB_MAX)
484 return -ENXIO;
485 num_registered_fb++;
486 for (i = 0 ; i < FB_MAX; i++)
487 if (!registered_fb[i])
488 break;
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
494 * many times
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;
502 if (first) {
503 first = 0;
504 take_over_console(&fb_con, 0, MAX_NR_CONSOLES-1, 1);
507 return 0;
511 unregister_framebuffer(const struct fb_info *fb_info)
513 int i, j;
515 i = GET_FB_IDX(fb_info->node);
516 for (j = 0; j < MAX_NR_CONSOLES; j++)
517 if (con2fb_map[j] == i)
518 return -EBUSY;
519 if (!registered_fb[i])
520 return -EINVAL;
521 registered_fb[i]=NULL;
522 num_registered_fb--;
523 return 0;
526 #ifdef CONFIG_PROC_FS
527 static struct proc_dir_entry *proc_fbmem;
528 #endif
530 __initfunc(void
531 fbmem_init(void))
533 int i;
535 #ifdef CONFIG_PROC_FS
536 proc_fbmem = create_proc_entry("fb", 0, 0);
537 if (proc_fbmem)
538 proc_fbmem->read_proc = fbmem_read_proc;
539 #endif
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)
559 #if 0
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;
569 if (!vpicos)
570 return 0;
572 if (monspecs->hfmin == 0)
573 return 1;
575 if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 ||
576 vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12)
577 return 0;
578 #endif
579 return 1;
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))
594 int i, j;
596 if (!options || !*options)
597 return;
599 if (!strncmp(options, "map:", 4)) {
600 options += 4;
601 if (*options)
602 for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
603 if (!options[j])
604 j = 0;
605 con2fb_map[i] = (options[j++]-'0') % FB_MAX;
607 return;
610 if (num_pref_init_funcs == FB_MAX)
611 return;
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) &&
616 options[j] == ':') {
617 if (!strcmp(options+j+1, "off"))
618 fb_drivers[i].init = NULL;
619 else {
620 if (fb_drivers[i].init) {
621 pref_init_funcs[num_pref_init_funcs++] =
622 fb_drivers[i].init;
623 fb_drivers[i].init = NULL;
625 if (fb_drivers[i].setup)
626 fb_drivers[i].setup(options+j+1, ints);
628 return;
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
634 * function.
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++] =
639 fb_drivers[i].init;
640 fb_drivers[i].init = NULL;
642 fb_drivers[i].setup(options, ints);
643 return;
650 * Visible symbols for modules
653 EXPORT_SYMBOL(register_framebuffer);
654 EXPORT_SYMBOL(unregister_framebuffer);