2 * linux/drivers/video/vfb.c -- Virtual frame buffer device
4 * Copyright (C) 2002 James Simmons
6 * Copyright (C) 1997 Geert Uytterhoeven
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
18 #include <linux/tty.h>
19 #include <linux/slab.h>
20 #include <linux/vmalloc.h>
21 #include <linux/delay.h>
22 #include <linux/interrupt.h>
23 #include <asm/uaccess.h>
25 #include <linux/init.h>
28 * RAM we reserve for the frame buffer. This defines the maximum screen
31 * The default can be overridden if the driver is compiled as a module
34 #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */
36 static void *videomemory
;
37 static u_long videomemorysize
= VIDEOMEMSIZE
;
38 MODULE_PARM(videomemorysize
, "l");
40 static struct fb_var_screeninfo vfb_default __initdata
= {
49 .activate
= FB_ACTIVATE_TEST
,
59 .vmode
= FB_VMODE_NONINTERLACED
,
62 static struct fb_fix_screeninfo vfb_fix __initdata
= {
64 .type
= FB_TYPE_PACKED_PIXELS
,
65 .visual
= FB_VISUAL_PSEUDOCOLOR
,
69 .accel
= FB_ACCEL_NONE
,
72 static int vfb_enable __initdata
= 0; /* disabled by default */
73 MODULE_PARM(vfb_enable
, "i");
76 * Interface used by the world
79 int vfb_setup(char *);
81 static int vfb_check_var(struct fb_var_screeninfo
*var
,
82 struct fb_info
*info
);
83 static int vfb_set_par(struct fb_info
*info
);
84 static int vfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
85 u_int transp
, struct fb_info
*info
);
86 static int vfb_pan_display(struct fb_var_screeninfo
*var
,
87 struct fb_info
*info
);
88 static int vfb_mmap(struct fb_info
*info
, struct file
*file
,
89 struct vm_area_struct
*vma
);
91 static struct fb_ops vfb_ops
= {
92 .fb_check_var
= vfb_check_var
,
93 .fb_set_par
= vfb_set_par
,
94 .fb_setcolreg
= vfb_setcolreg
,
95 .fb_pan_display
= vfb_pan_display
,
96 .fb_fillrect
= cfb_fillrect
,
97 .fb_copyarea
= cfb_copyarea
,
98 .fb_imageblit
= cfb_imageblit
,
99 .fb_cursor
= soft_cursor
,
107 static u_long
get_line_length(int xres_virtual
, int bpp
)
111 length
= xres_virtual
* bpp
;
112 length
= (length
+ 31) & ~31;
118 * Setting the video mode has been split into two parts.
119 * First part, xxxfb_check_var, must not write anything
120 * to hardware, it should only verify and adjust var.
121 * This means it doesn't alter par but it does use hardware
122 * data from it to check this var.
125 static int vfb_check_var(struct fb_var_screeninfo
*var
,
126 struct fb_info
*info
)
131 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
132 * as FB_VMODE_SMOOTH_XPAN is only used internally
135 if (var
->vmode
& FB_VMODE_CONUPDATE
) {
136 var
->vmode
|= FB_VMODE_YWRAP
;
137 var
->xoffset
= info
->var
.xoffset
;
138 var
->yoffset
= info
->var
.yoffset
;
142 * Some very basic checks
148 if (var
->xres
> var
->xres_virtual
)
149 var
->xres_virtual
= var
->xres
;
150 if (var
->yres
> var
->yres_virtual
)
151 var
->yres_virtual
= var
->yres
;
152 if (var
->bits_per_pixel
<= 1)
153 var
->bits_per_pixel
= 1;
154 else if (var
->bits_per_pixel
<= 8)
155 var
->bits_per_pixel
= 8;
156 else if (var
->bits_per_pixel
<= 16)
157 var
->bits_per_pixel
= 16;
158 else if (var
->bits_per_pixel
<= 24)
159 var
->bits_per_pixel
= 24;
160 else if (var
->bits_per_pixel
<= 32)
161 var
->bits_per_pixel
= 32;
165 if (var
->xres_virtual
< var
->xoffset
+ var
->xres
)
166 var
->xres_virtual
= var
->xoffset
+ var
->xres
;
167 if (var
->yres_virtual
< var
->yoffset
+ var
->yres
)
168 var
->yres_virtual
= var
->yoffset
+ var
->yres
;
174 get_line_length(var
->xres_virtual
, var
->bits_per_pixel
);
175 if (line_length
* var
->yres_virtual
> videomemorysize
)
179 * Now that we checked it we alter var. The reason being is that the video
180 * mode passed in might not work but slight changes to it might make it
181 * work. This way we let the user know what is acceptable.
183 switch (var
->bits_per_pixel
) {
188 var
->green
.offset
= 0;
189 var
->green
.length
= 8;
190 var
->blue
.offset
= 0;
191 var
->blue
.length
= 8;
192 var
->transp
.offset
= 0;
193 var
->transp
.length
= 0;
195 case 16: /* RGBA 5551 */
196 if (var
->transp
.length
) {
199 var
->green
.offset
= 5;
200 var
->green
.length
= 5;
201 var
->blue
.offset
= 10;
202 var
->blue
.length
= 5;
203 var
->transp
.offset
= 15;
204 var
->transp
.length
= 1;
205 } else { /* RGB 565 */
208 var
->green
.offset
= 5;
209 var
->green
.length
= 6;
210 var
->blue
.offset
= 11;
211 var
->blue
.length
= 5;
212 var
->transp
.offset
= 0;
213 var
->transp
.length
= 0;
216 case 24: /* RGB 888 */
219 var
->green
.offset
= 8;
220 var
->green
.length
= 8;
221 var
->blue
.offset
= 16;
222 var
->blue
.length
= 8;
223 var
->transp
.offset
= 0;
224 var
->transp
.length
= 0;
226 case 32: /* RGBA 8888 */
229 var
->green
.offset
= 8;
230 var
->green
.length
= 8;
231 var
->blue
.offset
= 16;
232 var
->blue
.length
= 8;
233 var
->transp
.offset
= 24;
234 var
->transp
.length
= 8;
237 var
->red
.msb_right
= 0;
238 var
->green
.msb_right
= 0;
239 var
->blue
.msb_right
= 0;
240 var
->transp
.msb_right
= 0;
245 /* This routine actually sets the video mode. It's in here where we
246 * the hardware state info->par and fix which can be affected by the
247 * change in par. For this driver it doesn't do much.
249 static int vfb_set_par(struct fb_info
*info
)
251 info
->fix
.line_length
= get_line_length(info
->var
.xres_virtual
,
252 info
->var
.bits_per_pixel
);
257 * Set a single color register. The values supplied are already
258 * rounded down to the hardware's capabilities (according to the
259 * entries in the var structure). Return != 0 for invalid regno.
262 static int vfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
263 u_int transp
, struct fb_info
*info
)
265 if (regno
>= 256) /* no. of hw registers */
268 * Program hardware... do anything you want with transp
271 /* grayscale works only partially under directcolor */
272 if (info
->var
.grayscale
) {
273 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
275 (red
* 77 + green
* 151 + blue
* 28) >> 8;
279 * var->{color}.offset contains start of bitfield
280 * var->{color}.length contains length of bitfield
281 * {hardwarespecific} contains width of RAMDAC
282 * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
283 * RAMDAC[X] is programmed to (red, green, blue)
286 * uses offset = 0 && length = RAMDAC register width.
287 * var->{color}.offset is 0
288 * var->{color}.length contains widht of DAC
290 * RAMDAC[X] is programmed to (red, green, blue)
292 * does not use DAC. Usually 3 are present.
293 * var->{color}.offset contains start of bitfield
294 * var->{color}.length contains length of bitfield
295 * cmap is programmed to (red << red.offset) | (green << green.offset) |
296 * (blue << blue.offset) | (transp << transp.offset)
297 * RAMDAC does not exist
299 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
300 switch (info
->fix
.visual
) {
301 case FB_VISUAL_TRUECOLOR
:
302 case FB_VISUAL_PSEUDOCOLOR
:
303 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
304 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
305 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
306 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
308 case FB_VISUAL_DIRECTCOLOR
:
309 red
= CNVT_TOHW(red
, 8); /* expect 8 bit DAC */
310 green
= CNVT_TOHW(green
, 8);
311 blue
= CNVT_TOHW(blue
, 8);
312 /* hey, there is bug in transp handling... */
313 transp
= CNVT_TOHW(transp
, 8);
317 /* Truecolor has hardware independent palette */
318 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
324 v
= (red
<< info
->var
.red
.offset
) |
325 (green
<< info
->var
.green
.offset
) |
326 (blue
<< info
->var
.blue
.offset
) |
327 (transp
<< info
->var
.transp
.offset
);
328 switch (info
->var
.bits_per_pixel
) {
332 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
336 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
345 * Pan or Wrap the Display
347 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
350 static int vfb_pan_display(struct fb_var_screeninfo
*var
,
351 struct fb_info
*info
)
353 if (var
->vmode
& FB_VMODE_YWRAP
) {
355 || var
->yoffset
>= info
->var
.yres_virtual
359 if (var
->xoffset
+ var
->xres
> info
->var
.xres_virtual
||
360 var
->yoffset
+ var
->yres
> info
->var
.yres_virtual
)
363 info
->var
.xoffset
= var
->xoffset
;
364 info
->var
.yoffset
= var
->yoffset
;
365 if (var
->vmode
& FB_VMODE_YWRAP
)
366 info
->var
.vmode
|= FB_VMODE_YWRAP
;
368 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
373 * Most drivers don't need their own mmap function
376 static int vfb_mmap(struct fb_info
*info
, struct file
*file
,
377 struct vm_area_struct
*vma
)
382 int __init
vfb_setup(char *options
)
388 if (!options
|| !*options
)
391 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
394 if (!strncmp(this_opt
, "disable", 7))
404 static void vfb_platform_release(struct device
*device
)
406 // This is called when the reference count goes to zero.
409 static int __init
vfb_probe(struct device
*device
)
411 struct platform_device
*dev
= to_platform_device(device
);
412 struct fb_info
*info
;
413 int retval
= -ENOMEM
;
416 * For real video cards we use ioremap.
418 if (!(videomemory
= vmalloc(videomemorysize
)))
422 * VFB must clear memory to prevent kernel info
423 * leakage into userspace
424 * VGA-based drivers MUST NOT clear memory if
425 * they want to be able to take over vgacon
427 memset(videomemory
, 0, videomemorysize
);
429 info
= framebuffer_alloc(sizeof(u32
) * 256, &dev
->dev
);
433 info
->screen_base
= videomemory
;
434 info
->fbops
= &vfb_ops
;
436 retval
= fb_find_mode(&info
->var
, info
, NULL
,
439 if (!retval
|| (retval
== 4))
440 info
->var
= vfb_default
;
442 info
->pseudo_palette
= info
->par
;
444 info
->flags
= FBINFO_FLAG_DEFAULT
;
446 retval
= fb_alloc_cmap(&info
->cmap
, 256, 0);
450 retval
= register_framebuffer(info
);
453 dev_set_drvdata(&dev
->dev
, info
);
456 "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
457 info
->node
, videomemorysize
>> 10);
460 fb_dealloc_cmap(&info
->cmap
);
462 framebuffer_release(info
);
468 static int vfb_remove(struct device
*device
)
470 struct fb_info
*info
= dev_get_drvdata(device
);
473 unregister_framebuffer(info
);
475 framebuffer_release(info
);
480 static struct device_driver vfb_driver
= {
482 .bus
= &platform_bus_type
,
484 .remove
= vfb_remove
,
487 static struct platform_device vfb_device
= {
491 .release
= vfb_platform_release
,
495 int __init
vfb_init(void)
502 if (fb_get_options("vfb", &option
))
510 ret
= driver_register(&vfb_driver
);
513 ret
= platform_device_register(&vfb_device
);
515 driver_unregister(&vfb_driver
);
520 module_init(vfb_init
);
523 static void __exit
vfb_exit(void)
525 platform_device_unregister(&vfb_device
);
526 driver_unregister(&vfb_driver
);
529 module_exit(vfb_exit
);
531 MODULE_LICENSE("GPL");