2 * linux/drivers/video/fbmem.c
4 * Copyright (C) 1994 Martin Schaller
6 * 2001 - Documented with DocBook
7 * - Brad Douglas <brad@neruo.com>
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive
14 #include <linux/config.h>
15 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/sched.h>
20 #include <linux/smp_lock.h>
21 #include <linux/kernel.h>
22 #include <linux/major.h>
23 #include <linux/slab.h>
25 #include <linux/mman.h>
26 #include <linux/tty.h>
27 #include <linux/init.h>
28 #include <linux/linux_logo.h>
29 #include <linux/proc_fs.h>
31 #include <linux/kmod.h>
33 #include <linux/devfs_fs_kernel.h>
35 #if defined(__mc68000__) || defined(CONFIG_APUS)
36 #include <asm/setup.h>
40 #include <asm/uaccess.h>
42 #include <asm/pgtable.h>
46 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
47 #include "console/fbcon.h"
50 * Frame buffer device initialization and setup routines
53 extern int acornfb_init(void);
54 extern int acornfb_setup(char*);
55 extern int amifb_init(void);
56 extern int amifb_setup(char*);
57 extern int anakinfb_init(void);
58 extern int atafb_init(void);
59 extern int atafb_setup(char*);
60 extern int macfb_init(void);
61 extern int macfb_setup(char*);
62 extern int cyberfb_init(void);
63 extern int cyberfb_setup(char*);
64 extern int pm2fb_init(void);
65 extern int pm2fb_setup(char*);
66 extern int pm3fb_init(void);
67 extern int pm3fb_setup(char*);
68 extern int clps711xfb_init(void);
69 extern int cyber2000fb_init(void);
70 extern int cyber2000fb_setup(char*);
71 extern int retz3fb_init(void);
72 extern int retz3fb_setup(char*);
73 extern int clgenfb_init(void);
74 extern int clgenfb_setup(char*);
75 extern int hitfb_init(void);
76 extern int vfb_init(void);
77 extern int vfb_setup(char*);
78 extern int offb_init(void);
79 extern int atyfb_init(void);
80 extern int atyfb_setup(char*);
81 extern int aty128fb_init(void);
82 extern int aty128fb_setup(char*);
83 extern int neofb_init(void);
84 extern int neofb_setup(char*);
85 extern int igafb_init(void);
86 extern int igafb_setup(char*);
87 extern int imsttfb_init(void);
88 extern int imsttfb_setup(char*);
89 extern int dnfb_init(void);
90 extern int tgafb_init(void);
91 extern int tgafb_setup(char*);
92 extern int virgefb_init(void);
93 extern int virgefb_setup(char*);
94 extern int resolver_video_setup(char*);
95 extern int s3triofb_init(void);
96 extern int vesafb_init(void);
97 extern int vesafb_setup(char*);
98 extern int vga16fb_init(void);
99 extern int vga16fb_setup(char*);
100 extern int hgafb_init(void);
101 extern int hgafb_setup(char*);
102 extern int matroxfb_init(void);
103 extern int matroxfb_setup(char*);
104 extern int hpfb_init(void);
105 extern int control_init(void);
106 extern int control_setup(char*);
107 extern int platinum_init(void);
108 extern int platinum_setup(char*);
109 extern int valkyriefb_init(void);
110 extern int valkyriefb_setup(char*);
111 extern int chips_init(void);
112 extern int g364fb_init(void);
113 extern int sa1100fb_init(void);
114 extern int fm2fb_init(void);
115 extern int fm2fb_setup(char*);
116 extern int q40fb_init(void);
117 extern int sun3fb_init(void);
118 extern int sun3fb_setup(char *);
119 extern int sgivwfb_init(void);
120 extern int sgivwfb_setup(char*);
121 extern int rivafb_init(void);
122 extern int rivafb_setup(char*);
123 extern int tdfxfb_init(void);
124 extern int tdfxfb_setup(char*);
125 extern int tridentfb_init(void);
126 extern int tridentfb_setup(char*);
127 extern int sisfb_init(void);
128 extern int sisfb_setup(char*);
129 extern int stifb_init(void);
130 extern int stifb_setup(char*);
131 extern int pmagbafb_init(void);
132 extern int pmagbbfb_init(void);
133 extern int maxinefb_init(void);
134 extern int tx3912fb_init(void);
135 extern int tx3912fb_setup(char*);
136 extern int radeonfb_init(void);
137 extern int radeonfb_setup(char*);
138 extern int e1355fb_init(void);
139 extern int e1355fb_setup(char*);
140 extern int pvr2fb_init(void);
141 extern int pvr2fb_setup(char*);
142 extern int sstfb_init(void);
143 extern int sstfb_setup(char*);
144 extern int i810fb_init(void);
145 extern int i810fb_setup(char*);
146 extern int ffb_init(void);
147 extern int ffb_setup(char*);
148 extern int cg6_init(void);
149 extern int cg6_setup(char*);
150 extern int cg3_init(void);
151 extern int cg3_setup(char*);
152 extern int bw2_init(void);
153 extern int bw2_setup(char*);
154 extern int cg14_init(void);
155 extern int cg14_setup(char*);
156 extern int p9100_init(void);
157 extern int p9100_setup(char*);
158 extern int tcx_init(void);
159 extern int tcx_setup(char*);
160 extern int leo_init(void);
161 extern int leo_setup(char*);
167 } fb_drivers
[] __initdata
= {
170 * Chipset specific drivers that use resource management
172 #ifdef CONFIG_FB_RETINAZ3
173 { "retz3fb", retz3fb_init
, retz3fb_setup
},
175 #ifdef CONFIG_FB_AMIGA
176 { "amifb", amifb_init
, amifb_setup
},
178 #ifdef CONFIG_FB_ANAKIN
179 { "anakinfb", anakinfb_init
, NULL
},
181 #ifdef CONFIG_FB_CLPS711X
182 { "clps711xfb", clps711xfb_init
, NULL
},
184 #ifdef CONFIG_FB_CYBER
185 { "cyberfb", cyberfb_init
, cyberfb_setup
},
187 #ifdef CONFIG_FB_CYBER2000
188 { "cyber2000fb", cyber2000fb_init
, cyber2000fb_setup
},
191 { "pm2fb", pm2fb_init
, pm2fb_setup
},
194 { "pm3fb", pm3fb_init
, pm3fb_setup
},
196 #ifdef CONFIG_FB_CLGEN
197 { "clgenfb", clgenfb_init
, clgenfb_setup
},
200 { "atyfb", atyfb_init
, atyfb_setup
},
202 #ifdef CONFIG_FB_MATROX
203 { "matroxfb", matroxfb_init
, matroxfb_setup
},
205 #ifdef CONFIG_FB_ATY128
206 { "aty128fb", aty128fb_init
, aty128fb_setup
},
208 #ifdef CONFIG_FB_NEOMAGIC
209 { "neofb", neofb_init
, neofb_setup
},
211 #ifdef CONFIG_FB_VIRGE
212 { "virgefb", virgefb_init
, virgefb_setup
},
214 #ifdef CONFIG_FB_RIVA
215 { "rivafb", rivafb_init
, rivafb_setup
},
217 #ifdef CONFIG_FB_3DFX
218 { "tdfxfb", tdfxfb_init
, tdfxfb_setup
},
220 #ifdef CONFIG_FB_RADEON
221 { "radeonfb", radeonfb_init
, radeonfb_setup
},
223 #ifdef CONFIG_FB_CONTROL
224 { "controlfb", control_init
, control_setup
},
226 #ifdef CONFIG_FB_PLATINUM
227 { "platinumfb", platinum_init
, platinum_setup
},
229 #ifdef CONFIG_FB_VALKYRIE
230 { "valkyriefb", valkyriefb_init
, valkyriefb_setup
},
232 #ifdef CONFIG_FB_CT65550
233 { "chipsfb", chips_init
, NULL
},
235 #ifdef CONFIG_FB_IMSTT
236 { "imsttfb", imsttfb_init
, imsttfb_setup
},
238 #ifdef CONFIG_FB_S3TRIO
239 { "s3triofb", s3triofb_init
, NULL
},
242 { "fm2fb", fm2fb_init
, fm2fb_setup
},
245 { "sisfb", sisfb_init
, sisfb_setup
},
247 #ifdef CONFIG_FB_TRIDENT
248 { "tridentfb", tridentfb_init
, tridentfb_setup
},
250 #ifdef CONFIG_FB_I810
251 { "i810fb", i810fb_init
, i810fb_setup
},
254 { "stifb", stifb_init
, stifb_setup
},
257 { "ffb", ffb_init
, ffb_setup
},
260 { "cg6fb", cg6_init
, cg6_setup
},
263 { "cg3fb", cg3_init
, cg3_setup
},
266 { "bw2fb", bw2_init
, bw2_setup
},
268 #ifdef CONFIG_FB_CG14
269 { "cg14fb", cg14_init
, cg14_setup
},
271 #ifdef CONFIG_FB_P9100
272 { "p9100fb", p9100_init
, p9100_setup
},
275 { "tcxfb", tcx_init
, tcx_setup
},
278 { "leofb", leo_init
, leo_setup
},
282 * Generic drivers that are used as fallbacks
284 * These depend on resource management and must be initialized
285 * _after_ all other frame buffer devices that use resource
290 { "offb", offb_init
, NULL
},
292 #ifdef CONFIG_FB_VESA
293 { "vesafb", vesafb_init
, vesafb_setup
},
297 * Chipset specific drivers that don't use resource management (yet)
300 #ifdef CONFIG_FB_SGIVW
301 { "sgivwfb", sgivwfb_init
, sgivwfb_setup
},
303 #ifdef CONFIG_FB_ACORN
304 { "acornfb", acornfb_init
, acornfb_setup
},
306 #ifdef CONFIG_FB_ATARI
307 { "atafb", atafb_init
, atafb_setup
},
310 { "macfb", macfb_init
, macfb_setup
},
313 { "hgafb", hgafb_init
, hgafb_setup
},
316 { "igafb", igafb_init
, igafb_setup
},
319 { "apollofb", dnfb_init
, NULL
},
322 { "q40fb", q40fb_init
, NULL
},
325 { "tgafb", tgafb_init
, tgafb_setup
},
327 #ifdef CONFIG_FB_HP300
328 { "hpfb", hpfb_init
, NULL
},
330 #ifdef CONFIG_FB_G364
331 { "g364fb", g364fb_init
, NULL
},
333 #ifdef CONFIG_FB_SA1100
334 { "sa1100fb", sa1100fb_init
, NULL
},
336 #ifdef CONFIG_FB_SUN3
337 { "sun3fb", sun3fb_init
, sun3fb_setup
},
340 { "hitfb", hitfb_init
, NULL
},
342 #ifdef CONFIG_FB_TX3912
343 { "tx3912fb", tx3912fb_init
, tx3912fb_setup
},
345 #ifdef CONFIG_FB_E1355
346 { "e1355fb", e1355fb_init
, e1355fb_setup
},
348 #ifdef CONFIG_FB_PVR2
349 { "pvr2fb", pvr2fb_init
, pvr2fb_setup
},
351 #ifdef CONFIG_FB_PMAG_BA
352 { "pmagbafb", pmagbafb_init
, NULL
},
354 #ifdef CONFIG_FB_PMAGB_B
355 { "pmagbbfb", pmagbbfb_init
, NULL
},
357 #ifdef CONFIG_FB_MAXINE
358 { "maxinefb", maxinefb_init
, NULL
},
360 #ifdef CONFIG_FB_VOODOO1
361 { "sstfb", sstfb_init
, sstfb_setup
},
364 * Generic drivers that don't use resource management (yet)
367 #ifdef CONFIG_FB_VGA16
368 { "vga16fb", vga16fb_init
, vga16fb_setup
},
371 #ifdef CONFIG_GSP_RESOLVER
372 /* Not a real frame buffer device... */
373 { "resolverfb", NULL
, resolver_video_setup
},
376 #ifdef CONFIG_FB_VIRTUAL
378 * Vfb must be last to avoid that it becomes your primary display if
379 * other display devices are present
381 { "vfb", vfb_init
, vfb_setup
},
385 #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
386 #define FBPIXMAPSIZE 8192
388 extern const char *global_mode_option
;
390 static initcall_t pref_init_funcs
[FB_MAX
];
391 static int num_pref_init_funcs __initdata
= 0;
392 struct fb_info
*registered_fb
[FB_MAX
];
393 int num_registered_fb
;
396 static int ofonly __initdata
= 0;
402 u8
sys_inbuf(u8
*src
)
407 void sys_outbuf(u8
*src
, u8
*dst
, unsigned int size
)
409 memcpy(dst
, src
, size
);
412 void move_buf_aligned(struct fb_info
*info
, u8
*dst
, u8
*src
, u32 d_pitch
,
413 u32 s_pitch
, u32 height
)
417 for (i
= height
; i
--; ) {
418 info
->pixmap
.outbuf(src
, dst
, s_pitch
);
424 void move_buf_unaligned(struct fb_info
*info
, u8
*dst
, u8
*src
, u32 d_pitch
,
425 u32 height
, u32 mask
, u32 shift_high
, u32 shift_low
,
431 for (i
= height
; i
--; ) {
432 for (j
= 0; j
< idx
; j
++) {
433 tmp
= info
->pixmap
.inbuf(dst
+j
);
435 tmp
|= *src
>> shift_low
;
436 info
->pixmap
.outbuf(&tmp
, dst
+j
, 1);
437 tmp
= *src
<< shift_high
;
438 info
->pixmap
.outbuf(&tmp
, dst
+j
+1, 1);
441 tmp
= info
->pixmap
.inbuf(dst
+idx
);
443 tmp
|= *src
>> shift_low
;
444 info
->pixmap
.outbuf(&tmp
, dst
+idx
, 1);
445 if (shift_high
< mod
) {
446 tmp
= *src
<< shift_high
;
447 info
->pixmap
.outbuf(&tmp
, dst
+idx
+1, 1);
455 * we need to lock this section since fb_cursor
456 * may use fb_imageblit()
458 u32
fb_get_buffer_offset(struct fb_info
*info
, u32 size
)
460 u32 align
= info
->pixmap
.buf_align
- 1;
461 u32 offset
, count
= 1000;
463 spin_lock(&info
->pixmap
.lock
);
464 offset
= info
->pixmap
.offset
+ align
;
466 if (offset
+ size
> info
->pixmap
.size
) {
467 while (atomic_read(&info
->pixmap
.count
) && count
--);
468 if (info
->fbops
->fb_sync
&&
469 info
->pixmap
.flags
& FB_PIXMAP_SYNC
)
470 info
->fbops
->fb_sync(info
);
473 info
->pixmap
.offset
= offset
+ size
;
474 atomic_inc(&info
->pixmap
.count
);
475 smp_mb__after_atomic_inc();
476 spin_unlock(&info
->pixmap
.lock
);
481 #include <linux/linux_logo.h>
483 static inline unsigned safe_shift(unsigned d
, int n
)
485 return n
< 0 ? d
>> -n
: d
<< n
;
488 static void __init
fb_set_logocmap(struct fb_info
*info
,
489 const struct linux_logo
*logo
)
491 struct fb_cmap palette_cmap
;
492 u16 palette_green
[16];
493 u16 palette_blue
[16];
496 const unsigned char *clut
= logo
->clut
;
498 palette_cmap
.start
= 0;
499 palette_cmap
.len
= 16;
500 palette_cmap
.red
= palette_red
;
501 palette_cmap
.green
= palette_green
;
502 palette_cmap
.blue
= palette_blue
;
503 palette_cmap
.transp
= NULL
;
505 for (i
= 0; i
< logo
->clutsize
; i
+= n
) {
506 n
= logo
->clutsize
- i
;
507 /* palette_cmap provides space for only 16 colors at once */
510 palette_cmap
.start
= 32 + i
;
511 palette_cmap
.len
= n
;
512 for (j
= 0; j
< n
; ++j
) {
513 palette_cmap
.red
[j
] = clut
[0] << 8 | clut
[0];
514 palette_cmap
.green
[j
] = clut
[1] << 8 | clut
[1];
515 palette_cmap
.blue
[j
] = clut
[2] << 8 | clut
[2];
518 fb_set_cmap(&palette_cmap
, 1, info
);
522 static void __init
fb_set_logo_truepalette(struct fb_info
*info
,
523 const struct linux_logo
*logo
,
526 unsigned char mask
[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
527 unsigned char redmask
, greenmask
, bluemask
;
528 int redshift
, greenshift
, blueshift
;
530 const unsigned char *clut
= logo
->clut
;
533 * We have to create a temporary palette since console palette is only
536 /* Bug: Doesn't obey msb_right ... (who needs that?) */
537 redmask
= mask
[info
->var
.red
.length
< 8 ? info
->var
.red
.length
: 8];
538 greenmask
= mask
[info
->var
.green
.length
< 8 ? info
->var
.green
.length
: 8];
539 bluemask
= mask
[info
->var
.blue
.length
< 8 ? info
->var
.blue
.length
: 8];
540 redshift
= info
->var
.red
.offset
- (8 - info
->var
.red
.length
);
541 greenshift
= info
->var
.green
.offset
- (8 - info
->var
.green
.length
);
542 blueshift
= info
->var
.blue
.offset
- (8 - info
->var
.blue
.length
);
544 for ( i
= 0; i
< logo
->clutsize
; i
++) {
545 palette
[i
+32] = (safe_shift((clut
[0] & redmask
), redshift
) |
546 safe_shift((clut
[1] & greenmask
), greenshift
) |
547 safe_shift((clut
[2] & bluemask
), blueshift
));
552 static void __init
fb_set_logo_directpalette(struct fb_info
*info
,
553 const struct linux_logo
*logo
,
556 int redshift
, greenshift
, blueshift
;
559 redshift
= info
->var
.red
.offset
;
560 greenshift
= info
->var
.green
.offset
;
561 blueshift
= info
->var
.blue
.offset
;
563 for (i
= 32; i
< logo
->clutsize
; i
++)
564 palette
[i
] = i
<< redshift
| i
<< greenshift
| i
<< blueshift
;
567 static void __init
fb_set_logo(struct fb_info
*info
,
568 const struct linux_logo
*logo
, u8
*dst
,
572 const u8
*src
= logo
->data
;
577 for (i
= 0; i
< logo
->height
; i
++)
578 for (j
= 0; j
< logo
->width
; src
++) {
581 if (j
< logo
->width
) {
582 *dst
++ = *src
& 0x0f;
590 for (i
= 0; i
< logo
->height
; i
++) {
593 for (j
= 0; j
< logo
->width
; j
++) {
594 *dst
++ = (d
>> shift
) & 1;
595 shift
= (shift
-1) & 7;
605 * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors),
606 * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on
607 * the visual format and color depth of the framebuffer, the DAC, the
608 * pseudo_palette, and the logo data will be adjusted accordingly.
610 * Case 1 - linux_logo_clut224:
611 * Color exceeds the number of console colors (16), thus we set the hardware DAC
612 * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set.
614 * For visuals that require color info from the pseudo_palette, we also construct
615 * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
618 * Case 2 - linux_logo_vga16:
619 * The number of colors just matches the console colors, thus there is no need
620 * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie,
621 * each byte contains color information for two pixels (upper and lower nibble).
622 * To be consistent with fb_imageblit() usage, we therefore separate the two
623 * nibbles into separate bytes. The "depth" flag will be set to 4.
625 * Case 3 - linux_logo_mono:
626 * This is similar with Case 2. Each byte contains information for 8 pixels.
627 * We isolate each bit and expand each into a byte. The "depth" flag will
630 static struct logo_data
{
632 int needs_directpalette
;
633 int needs_truepalette
;
635 const struct linux_logo
*logo
;
638 int fb_prepare_logo(struct fb_info
*info
)
640 memset(&fb_logo
, 0, sizeof(struct logo_data
));
642 switch (info
->fix
.visual
) {
643 case FB_VISUAL_TRUECOLOR
:
644 if (info
->var
.bits_per_pixel
>= 8)
645 fb_logo
.needs_truepalette
= 1;
647 case FB_VISUAL_DIRECTCOLOR
:
648 if (info
->var
.bits_per_pixel
>= 24) {
649 fb_logo
.needs_directpalette
= 1;
650 fb_logo
.needs_cmapreset
= 1;
653 case FB_VISUAL_PSEUDOCOLOR
:
654 fb_logo
.needs_cmapreset
= 1;
658 /* Return if no suitable logo was found */
659 fb_logo
.logo
= fb_find_logo(info
->var
.bits_per_pixel
);
661 if (!fb_logo
.logo
|| fb_logo
.logo
->height
> info
->var
.yres
) {
665 /* What depth we asked for might be different from what we get */
666 if (fb_logo
.logo
->type
== LINUX_LOGO_CLUT224
)
668 else if (fb_logo
.logo
->type
== LINUX_LOGO_VGA16
)
672 return fb_logo
.logo
->height
;
675 int fb_show_logo(struct fb_info
*info
)
677 u32
*palette
= NULL
, *saved_pseudo_palette
= NULL
;
678 unsigned char *logo_new
= NULL
;
679 struct fb_image image
;
682 /* Return if the frame buffer is not mapped */
683 if (fb_logo
.logo
== NULL
)
686 image
.depth
= fb_logo
.depth
;
687 image
.data
= fb_logo
.logo
->data
;
689 if (fb_logo
.needs_cmapreset
)
690 fb_set_logocmap(info
, fb_logo
.logo
);
692 if (fb_logo
.needs_truepalette
||
693 fb_logo
.needs_directpalette
) {
694 palette
= kmalloc(256 * 4, GFP_KERNEL
);
698 if (fb_logo
.needs_truepalette
)
699 fb_set_logo_truepalette(info
, fb_logo
.logo
, palette
);
701 fb_set_logo_directpalette(info
, fb_logo
.logo
, palette
);
703 saved_pseudo_palette
= info
->pseudo_palette
;
704 info
->pseudo_palette
= palette
;
707 if (fb_logo
.depth
== 4) {
708 logo_new
= kmalloc(fb_logo
.logo
->width
* fb_logo
.logo
->height
,
710 if (logo_new
== NULL
) {
713 if (saved_pseudo_palette
)
714 info
->pseudo_palette
= saved_pseudo_palette
;
717 image
.data
= logo_new
;
718 fb_set_logo(info
, fb_logo
.logo
, logo_new
, fb_logo
.depth
);
721 image
.width
= fb_logo
.logo
->width
;
722 image
.height
= fb_logo
.logo
->height
;
725 for (x
= 0; x
< num_online_cpus() * (fb_logo
.logo
->width
+ 8) &&
726 x
<= info
->var
.xres
-fb_logo
.logo
->width
; x
+= (fb_logo
.logo
->width
+ 8)) {
728 info
->fbops
->fb_imageblit(info
, &image
);
729 //atomic_dec(&info->pixmap.count);
730 //smp_mb__after_atomic_dec();
735 if (saved_pseudo_palette
!= NULL
)
736 info
->pseudo_palette
= saved_pseudo_palette
;
737 if (logo_new
!= NULL
)
739 return fb_logo
.logo
->height
;
742 int fb_prepare_logo(struct fb_info
*info
) { return 0; }
743 int fb_show_logo(struct fb_info
*info
) { return 0; }
744 #endif /* CONFIG_LOGO */
746 static int fbmem_read_proc(char *buf
, char **start
, off_t offset
,
747 int len
, int *eof
, void *private)
753 for (fi
= registered_fb
; fi
< ®istered_fb
[FB_MAX
] && len
< 4000; fi
++)
755 clen
+= sprintf(buf
+ clen
, "%d %s\n",
758 *start
= buf
+ offset
;
763 return clen
< len
? clen
: len
;
767 fb_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
769 unsigned long p
= *ppos
;
770 struct inode
*inode
= file
->f_dentry
->d_inode
;
771 int fbidx
= iminor(inode
);
772 struct fb_info
*info
= registered_fb
[fbidx
];
774 if (!info
|| ! info
->screen_base
)
777 if (info
->fbops
->fb_read
)
778 return info
->fbops
->fb_read(file
, buf
, count
, ppos
);
780 if (p
>= info
->fix
.smem_len
)
782 if (count
>= info
->fix
.smem_len
)
783 count
= info
->fix
.smem_len
;
784 if (count
+ p
> info
->fix
.smem_len
)
785 count
= info
->fix
.smem_len
- p
;
786 if (info
->fbops
->fb_sync
)
787 info
->fbops
->fb_sync(info
);
791 base_addr
= info
->screen_base
;
792 count
-= copy_to_user(buf
, base_addr
+p
, count
);
801 fb_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
803 unsigned long p
= *ppos
;
804 struct inode
*inode
= file
->f_dentry
->d_inode
;
805 int fbidx
= iminor(inode
);
806 struct fb_info
*info
= registered_fb
[fbidx
];
809 if (!info
|| !info
->screen_base
)
812 if (info
->fbops
->fb_write
)
813 return info
->fbops
->fb_write(file
, buf
, count
, ppos
);
815 if (p
> info
->fix
.smem_len
)
817 if (count
>= info
->fix
.smem_len
)
818 count
= info
->fix
.smem_len
;
820 if (count
+ p
> info
->fix
.smem_len
) {
821 count
= info
->fix
.smem_len
- p
;
824 if (info
->fbops
->fb_sync
)
825 info
->fbops
->fb_sync(info
);
829 base_addr
= info
->screen_base
;
830 count
-= copy_from_user(base_addr
+p
, buf
, count
);
840 static void try_to_load(int fb
)
842 request_module("fb%d", fb
);
844 #endif /* CONFIG_KMOD */
847 fb_cursor(struct fb_info
*info
, struct fb_cursor
*sprite
)
849 struct fb_cursor cursor
;
852 if (copy_from_user(&cursor
, sprite
, sizeof(struct fb_cursor
)))
855 if (cursor
.set
& FB_CUR_SETCUR
)
856 info
->cursor
.enable
= 1;
858 if (cursor
.set
& FB_CUR_SETCMAP
) {
859 err
= fb_copy_cmap(&cursor
.image
.cmap
, &sprite
->image
.cmap
, 1);
864 if (cursor
.set
& FB_CUR_SETSHAPE
) {
865 int size
= ((cursor
.image
.width
+ 7) >> 3) * cursor
.image
.height
;
866 if ((cursor
.image
.height
!= info
->cursor
.image
.height
) ||
867 (cursor
.image
.width
!= info
->cursor
.image
.width
))
868 cursor
.set
|= FB_CUR_SETSIZE
;
870 cursor
.image
.data
= kmalloc(size
, GFP_KERNEL
);
871 if (!cursor
.image
.data
)
874 cursor
.mask
= kmalloc(size
, GFP_KERNEL
);
876 kfree(cursor
.image
.data
);
880 if (copy_from_user(&cursor
.image
.data
, sprite
->image
.data
, size
) ||
881 copy_from_user(cursor
.mask
, sprite
->mask
, size
)) {
882 kfree(cursor
.image
.data
);
887 info
->cursor
.set
= cursor
.set
;
888 info
->cursor
.rop
= cursor
.rop
;
889 err
= info
->fbops
->fb_cursor(info
, &cursor
);
894 fb_pan_display(struct fb_info
*info
, struct fb_var_screeninfo
*var
)
896 int xoffset
= var
->xoffset
;
897 int yoffset
= var
->yoffset
;
900 if (xoffset
< 0 || yoffset
< 0 || !info
->fbops
->fb_pan_display
||
901 xoffset
+ info
->var
.xres
> info
->var
.xres_virtual
||
902 yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
)
904 if ((err
= info
->fbops
->fb_pan_display(var
, info
)))
906 info
->var
.xoffset
= var
->xoffset
;
907 info
->var
.yoffset
= var
->yoffset
;
908 if (var
->vmode
& FB_VMODE_YWRAP
)
909 info
->var
.vmode
|= FB_VMODE_YWRAP
;
911 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
916 fb_set_var(struct fb_info
*info
, struct fb_var_screeninfo
*var
)
920 if (memcmp(&info
->var
, var
, sizeof(struct fb_var_screeninfo
))) {
921 if (!info
->fbops
->fb_check_var
) {
926 if ((err
= info
->fbops
->fb_check_var(var
, info
)))
929 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
932 if (info
->fbops
->fb_set_par
)
933 info
->fbops
->fb_set_par(info
);
935 fb_pan_display(info
, &info
->var
);
937 fb_set_cmap(&info
->cmap
, 1, info
);
944 fb_blank(struct fb_info
*info
, int blank
)
946 /* ??? Variable sized stack allocation. */
947 u16 black
[info
->cmap
.len
];
950 if (info
->fbops
->fb_blank
&& !info
->fbops
->fb_blank(blank
, info
))
953 memset(black
, 0, info
->cmap
.len
* sizeof(u16
));
954 cmap
.red
= cmap
.green
= cmap
.blue
= black
;
955 cmap
.transp
= info
->cmap
.transp
? black
: NULL
;
956 cmap
.start
= info
->cmap
.start
;
957 cmap
.len
= info
->cmap
.len
;
960 return fb_set_cmap(&cmap
, 1, info
);
964 fb_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
967 int fbidx
= iminor(inode
);
968 struct fb_info
*info
= registered_fb
[fbidx
];
969 struct fb_ops
*fb
= info
->fbops
;
970 struct fb_var_screeninfo var
;
971 struct fb_fix_screeninfo fix
;
972 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
973 struct fb_con2fbmap con2fb
;
981 case FBIOGET_VSCREENINFO
:
982 return copy_to_user((void *) arg
, &info
->var
,
983 sizeof(var
)) ? -EFAULT
: 0;
984 case FBIOPUT_VSCREENINFO
:
985 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
987 i
= fb_set_var(info
, &var
);
989 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
992 case FBIOGET_FSCREENINFO
:
993 return copy_to_user((void *) arg
, &info
->fix
,
994 sizeof(fix
)) ? -EFAULT
: 0;
996 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
998 return (fb_set_cmap(&cmap
, 0, info
));
1000 if (copy_from_user(&cmap
, (void *) arg
, sizeof(cmap
)))
1002 return (fb_copy_cmap(&info
->cmap
, &cmap
, 0));
1003 case FBIOPAN_DISPLAY
:
1004 if (copy_from_user(&var
, (void *) arg
, sizeof(var
)))
1006 if ((i
= fb_pan_display(info
, &var
)))
1008 if (copy_to_user((void *) arg
, &var
, sizeof(var
)))
1012 return (fb_cursor(info
, (struct fb_cursor
*) arg
));
1013 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
1014 case FBIOGET_CON2FBMAP
:
1015 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
1017 if (con2fb
.console
< 1 || con2fb
.console
> MAX_NR_CONSOLES
)
1019 con2fb
.framebuffer
= con2fb_map
[con2fb
.console
-1];
1020 return copy_to_user((void *)arg
, &con2fb
,
1021 sizeof(con2fb
)) ? -EFAULT
: 0;
1022 case FBIOPUT_CON2FBMAP
:
1023 if (copy_from_user(&con2fb
, (void *)arg
, sizeof(con2fb
)))
1025 if (con2fb
.console
< 0 || con2fb
.console
> MAX_NR_CONSOLES
)
1027 if (con2fb
.framebuffer
< 0 || con2fb
.framebuffer
>= FB_MAX
)
1030 if (!registered_fb
[con2fb
.framebuffer
])
1031 try_to_load(con2fb
.framebuffer
);
1032 #endif /* CONFIG_KMOD */
1033 if (!registered_fb
[con2fb
.framebuffer
])
1035 if (con2fb
.console
!= 0)
1036 set_con2fb_map(con2fb
.console
-1, con2fb
.framebuffer
);
1040 #endif /* CONFIG_FRAMEBUFFER_CONSOLE */
1042 return fb_blank(info
, arg
);
1044 if (fb
->fb_ioctl
== NULL
)
1046 return fb
->fb_ioctl(inode
, file
, cmd
, arg
, info
);
1051 fb_mmap(struct file
*file
, struct vm_area_struct
* vma
)
1053 int fbidx
= iminor(file
->f_dentry
->d_inode
);
1054 struct fb_info
*info
= registered_fb
[fbidx
];
1055 struct fb_ops
*fb
= info
->fbops
;
1057 #if !defined(__sparc__) || defined(__sparc_v9__)
1058 unsigned long start
;
1062 if (vma
->vm_pgoff
> (~0UL >> PAGE_SHIFT
))
1064 off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
1070 res
= fb
->fb_mmap(info
, file
, vma
);
1075 #if defined(__sparc__) && !defined(__sparc_v9__)
1076 /* Should never get here, all fb drivers should have their own
1083 /* frame buffer memory */
1084 start
= info
->fix
.smem_start
;
1085 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + info
->fix
.smem_len
);
1087 /* memory mapped io */
1089 if (info
->var
.accel_flags
) {
1093 start
= info
->fix
.mmio_start
;
1094 len
= PAGE_ALIGN((start
& ~PAGE_MASK
) + info
->fix
.mmio_len
);
1098 if ((vma
->vm_end
- vma
->vm_start
+ off
) > len
)
1101 vma
->vm_pgoff
= off
>> PAGE_SHIFT
;
1102 /* This is an IO map - tell maydump to skip this VMA */
1103 vma
->vm_flags
|= VM_IO
;
1104 #if defined(__sparc_v9__)
1105 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
);
1106 if (io_remap_page_range(vma
, vma
->vm_start
, off
,
1107 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
, 0))
1110 #if defined(__mc68000__)
1111 #if defined(CONFIG_SUN3)
1112 pgprot_val(vma
->vm_page_prot
) |= SUN3_PAGE_NOCACHE
;
1113 #elif defined(CONFIG_MMU)
1114 if (CPU_IS_020_OR_030
)
1115 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE030
;
1116 if (CPU_IS_040_OR_060
) {
1117 pgprot_val(vma
->vm_page_prot
) &= _CACHEMASK040
;
1118 /* Use no-cache mode, serialized */
1119 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NOCACHE_S
;
1122 #elif defined(__powerpc__)
1123 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NO_CACHE
|_PAGE_GUARDED
;
1124 #elif defined(__alpha__)
1125 /* Caching is off in the I/O space quadrant by design. */
1126 #elif defined(__i386__) || defined(__x86_64__)
1127 if (boot_cpu_data
.x86
> 3)
1128 pgprot_val(vma
->vm_page_prot
) |= _PAGE_PCD
;
1129 #elif defined(__mips__)
1130 pgprot_val(vma
->vm_page_prot
) &= ~_CACHE_MASK
;
1131 pgprot_val(vma
->vm_page_prot
) |= _CACHE_UNCACHED
;
1132 #elif defined(__sh__)
1133 pgprot_val(vma
->vm_page_prot
) &= ~_PAGE_CACHABLE
;
1134 #elif defined(__hppa__)
1135 pgprot_val(vma
->vm_page_prot
) |= _PAGE_NO_CACHE
;
1136 #elif defined(__ia64__) || defined(__arm__)
1137 vma
->vm_page_prot
= pgprot_writecombine(vma
->vm_page_prot
);
1139 #warning What do we have to do here??
1141 if (io_remap_page_range(vma
, vma
->vm_start
, off
,
1142 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
1144 #endif /* !__sparc_v9__ */
1146 #endif /* !sparc32 */
1150 fb_open(struct inode
*inode
, struct file
*file
)
1152 int fbidx
= iminor(inode
);
1153 struct fb_info
*info
;
1156 if (fbidx
>= FB_MAX
)
1159 if (!(info
= registered_fb
[fbidx
]))
1161 #endif /* CONFIG_KMOD */
1162 if (!(info
= registered_fb
[fbidx
]))
1164 if (!try_module_get(info
->fbops
->owner
))
1166 if (info
->fbops
->fb_open
) {
1167 res
= info
->fbops
->fb_open(info
,1);
1169 module_put(info
->fbops
->owner
);
1175 fb_release(struct inode
*inode
, struct file
*file
)
1177 int fbidx
= iminor(inode
);
1178 struct fb_info
*info
;
1181 info
= registered_fb
[fbidx
];
1182 if (info
->fbops
->fb_release
)
1183 info
->fbops
->fb_release(info
,1);
1184 module_put(info
->fbops
->owner
);
1189 static struct file_operations fb_fops
= {
1190 .owner
= THIS_MODULE
,
1196 .release
= fb_release
,
1197 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1198 .get_unmapped_area
= get_fb_unmapped_area
,
1203 * register_framebuffer - registers a frame buffer device
1204 * @fb_info: frame buffer info structure
1206 * Registers a frame buffer device @fb_info.
1208 * Returns negative errno on error, or zero for success.
1213 register_framebuffer(struct fb_info
*fb_info
)
1217 if (num_registered_fb
== FB_MAX
)
1219 num_registered_fb
++;
1220 for (i
= 0 ; i
< FB_MAX
; i
++)
1221 if (!registered_fb
[i
])
1225 if (fb_info
->pixmap
.addr
== NULL
) {
1226 fb_info
->pixmap
.addr
= kmalloc(FBPIXMAPSIZE
, GFP_KERNEL
);
1227 if (fb_info
->pixmap
.addr
) {
1228 fb_info
->pixmap
.size
= FBPIXMAPSIZE
;
1229 fb_info
->pixmap
.buf_align
= 1;
1230 fb_info
->pixmap
.scan_align
= 1;
1231 fb_info
->pixmap
.flags
= FB_PIXMAP_DEFAULT
;
1234 fb_info
->pixmap
.offset
= 0;
1235 if (fb_info
->pixmap
.outbuf
== NULL
)
1236 fb_info
->pixmap
.outbuf
= sys_outbuf
;
1237 if (fb_info
->pixmap
.inbuf
== NULL
)
1238 fb_info
->pixmap
.inbuf
= sys_inbuf
;
1239 spin_lock_init(&fb_info
->pixmap
.lock
);
1241 registered_fb
[i
] = fb_info
;
1243 devfs_mk_cdev(MKDEV(FB_MAJOR
, i
),
1244 S_IFCHR
| S_IRUGO
| S_IWUGO
, "fb/%d", i
);
1250 * unregister_framebuffer - releases a frame buffer device
1251 * @fb_info: frame buffer info structure
1253 * Unregisters a frame buffer device @fb_info.
1255 * Returns negative errno on error, or zero for success.
1260 unregister_framebuffer(struct fb_info
*fb_info
)
1265 if (!registered_fb
[i
])
1267 devfs_remove("fb/%d", i
);
1269 if (fb_info
->pixmap
.addr
)
1270 kfree(fb_info
->pixmap
.addr
);
1271 registered_fb
[i
]=NULL
;
1272 num_registered_fb
--;
1278 * fbmem_init - init frame buffer subsystem
1280 * Initialize the frame buffer subsystem.
1282 * NOTE: This function is _only_ to be called by drivers/char/mem.c.
1291 create_proc_read_entry("fb", 0, 0, fbmem_read_proc
, NULL
);
1294 if (register_chrdev(FB_MAJOR
,"fb",&fb_fops
))
1295 printk("unable to get major %d for fb devs\n", FB_MAJOR
);
1305 * Probe for all builtin frame buffer devices
1307 for (i
= 0; i
< num_pref_init_funcs
; i
++)
1308 pref_init_funcs
[i
]();
1310 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++)
1311 if (fb_drivers
[i
].init
)
1312 fb_drivers
[i
].init();
1317 * video_setup - process command line options
1318 * @options: string of options
1320 * Process command line options for frame buffer subsystem.
1322 * NOTE: This function is a __setup and __init function.
1328 int __init
video_setup(char *options
)
1332 if (!options
|| !*options
)
1336 if (!strcmp(options
, "ofonly")) {
1342 if (num_pref_init_funcs
== FB_MAX
)
1345 for (i
= 0; i
< NUM_FB_DRIVERS
; i
++) {
1346 j
= strlen(fb_drivers
[i
].name
);
1347 if (!strncmp(options
, fb_drivers
[i
].name
, j
) &&
1348 options
[j
] == ':') {
1349 if (!strcmp(options
+j
+1, "off"))
1350 fb_drivers
[i
].init
= NULL
;
1352 if (fb_drivers
[i
].init
) {
1353 pref_init_funcs
[num_pref_init_funcs
++] =
1355 fb_drivers
[i
].init
= NULL
;
1357 if (fb_drivers
[i
].setup
)
1358 fb_drivers
[i
].setup(options
+j
+1);
1365 * If we get here no fb was specified.
1366 * We consider the argument to be a global video mode option.
1368 global_mode_option
= options
;
1372 __setup("video=", video_setup
);
1375 * Visible symbols for modules
1378 EXPORT_SYMBOL(register_framebuffer
);
1379 EXPORT_SYMBOL(unregister_framebuffer
);
1380 EXPORT_SYMBOL(num_registered_fb
);
1381 EXPORT_SYMBOL(registered_fb
);
1382 EXPORT_SYMBOL(fb_prepare_logo
);
1383 EXPORT_SYMBOL(fb_show_logo
);
1384 EXPORT_SYMBOL(fb_set_var
);
1385 EXPORT_SYMBOL(fb_blank
);
1386 EXPORT_SYMBOL(fb_pan_display
);
1387 EXPORT_SYMBOL(fb_get_buffer_offset
);
1388 EXPORT_SYMBOL(move_buf_unaligned
);
1389 EXPORT_SYMBOL(move_buf_aligned
);
1391 MODULE_LICENSE("GPL");