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/vmalloc.h>
19 #include <linux/delay.h>
20 #include <linux/interrupt.h>
21 #include <linux/platform_device.h>
24 #include <linux/init.h>
27 * RAM we reserve for the frame buffer. This defines the maximum screen
30 * The default can be overridden if the driver is compiled as a module
33 #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */
35 static void *videomemory
;
36 static u_long videomemorysize
= VIDEOMEMSIZE
;
37 module_param(videomemorysize
, ulong
, 0);
38 MODULE_PARM_DESC(videomemorysize
, "RAM available to frame buffer (in bytes)");
40 static char *mode_option
= NULL
;
41 module_param(mode_option
, charp
, 0);
42 MODULE_PARM_DESC(mode_option
, "Preferred video mode (e.g. 640x480-8@60)");
44 static const struct fb_videomode vfb_default
= {
54 .vmode
= FB_VMODE_NONINTERLACED
,
57 static struct fb_fix_screeninfo vfb_fix
= {
59 .type
= FB_TYPE_PACKED_PIXELS
,
60 .visual
= FB_VISUAL_PSEUDOCOLOR
,
64 .accel
= FB_ACCEL_NONE
,
67 static bool vfb_enable __initdata
= 0; /* disabled by default */
68 module_param(vfb_enable
, bool, 0);
69 MODULE_PARM_DESC(vfb_enable
, "Enable Virtual FB driver");
71 static int vfb_check_var(struct fb_var_screeninfo
*var
,
72 struct fb_info
*info
);
73 static int vfb_set_par(struct fb_info
*info
);
74 static int vfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
75 u_int transp
, struct fb_info
*info
);
76 static int vfb_pan_display(struct fb_var_screeninfo
*var
,
77 struct fb_info
*info
);
78 static int vfb_mmap(struct fb_info
*info
,
79 struct vm_area_struct
*vma
);
81 static struct fb_ops vfb_ops
= {
82 .fb_read
= fb_sys_read
,
83 .fb_write
= fb_sys_write
,
84 .fb_check_var
= vfb_check_var
,
85 .fb_set_par
= vfb_set_par
,
86 .fb_setcolreg
= vfb_setcolreg
,
87 .fb_pan_display
= vfb_pan_display
,
88 .fb_fillrect
= sys_fillrect
,
89 .fb_copyarea
= sys_copyarea
,
90 .fb_imageblit
= sys_imageblit
,
98 static u_long
get_line_length(int xres_virtual
, int bpp
)
102 length
= xres_virtual
* bpp
;
103 length
= (length
+ 31) & ~31;
109 * Setting the video mode has been split into two parts.
110 * First part, xxxfb_check_var, must not write anything
111 * to hardware, it should only verify and adjust var.
112 * This means it doesn't alter par but it does use hardware
113 * data from it to check this var.
116 static int vfb_check_var(struct fb_var_screeninfo
*var
,
117 struct fb_info
*info
)
122 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
123 * as FB_VMODE_SMOOTH_XPAN is only used internally
126 if (var
->vmode
& FB_VMODE_CONUPDATE
) {
127 var
->vmode
|= FB_VMODE_YWRAP
;
128 var
->xoffset
= info
->var
.xoffset
;
129 var
->yoffset
= info
->var
.yoffset
;
133 * Some very basic checks
139 if (var
->xres
> var
->xres_virtual
)
140 var
->xres_virtual
= var
->xres
;
141 if (var
->yres
> var
->yres_virtual
)
142 var
->yres_virtual
= var
->yres
;
143 if (var
->bits_per_pixel
<= 1)
144 var
->bits_per_pixel
= 1;
145 else if (var
->bits_per_pixel
<= 8)
146 var
->bits_per_pixel
= 8;
147 else if (var
->bits_per_pixel
<= 16)
148 var
->bits_per_pixel
= 16;
149 else if (var
->bits_per_pixel
<= 24)
150 var
->bits_per_pixel
= 24;
151 else if (var
->bits_per_pixel
<= 32)
152 var
->bits_per_pixel
= 32;
156 if (var
->xres_virtual
< var
->xoffset
+ var
->xres
)
157 var
->xres_virtual
= var
->xoffset
+ var
->xres
;
158 if (var
->yres_virtual
< var
->yoffset
+ var
->yres
)
159 var
->yres_virtual
= var
->yoffset
+ var
->yres
;
165 get_line_length(var
->xres_virtual
, var
->bits_per_pixel
);
166 if (line_length
* var
->yres_virtual
> videomemorysize
)
170 * Now that we checked it we alter var. The reason being is that the video
171 * mode passed in might not work but slight changes to it might make it
172 * work. This way we let the user know what is acceptable.
174 switch (var
->bits_per_pixel
) {
179 var
->green
.offset
= 0;
180 var
->green
.length
= 8;
181 var
->blue
.offset
= 0;
182 var
->blue
.length
= 8;
183 var
->transp
.offset
= 0;
184 var
->transp
.length
= 0;
186 case 16: /* RGBA 5551 */
187 if (var
->transp
.length
) {
190 var
->green
.offset
= 5;
191 var
->green
.length
= 5;
192 var
->blue
.offset
= 10;
193 var
->blue
.length
= 5;
194 var
->transp
.offset
= 15;
195 var
->transp
.length
= 1;
196 } else { /* RGB 565 */
199 var
->green
.offset
= 5;
200 var
->green
.length
= 6;
201 var
->blue
.offset
= 11;
202 var
->blue
.length
= 5;
203 var
->transp
.offset
= 0;
204 var
->transp
.length
= 0;
207 case 24: /* RGB 888 */
210 var
->green
.offset
= 8;
211 var
->green
.length
= 8;
212 var
->blue
.offset
= 16;
213 var
->blue
.length
= 8;
214 var
->transp
.offset
= 0;
215 var
->transp
.length
= 0;
217 case 32: /* RGBA 8888 */
220 var
->green
.offset
= 8;
221 var
->green
.length
= 8;
222 var
->blue
.offset
= 16;
223 var
->blue
.length
= 8;
224 var
->transp
.offset
= 24;
225 var
->transp
.length
= 8;
228 var
->red
.msb_right
= 0;
229 var
->green
.msb_right
= 0;
230 var
->blue
.msb_right
= 0;
231 var
->transp
.msb_right
= 0;
236 /* This routine actually sets the video mode. It's in here where we
237 * the hardware state info->par and fix which can be affected by the
238 * change in par. For this driver it doesn't do much.
240 static int vfb_set_par(struct fb_info
*info
)
242 switch (info
->var
.bits_per_pixel
) {
244 info
->fix
.visual
= FB_VISUAL_MONO01
;
247 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
252 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
256 info
->fix
.line_length
= get_line_length(info
->var
.xres_virtual
,
257 info
->var
.bits_per_pixel
);
263 * Set a single color register. The values supplied are already
264 * rounded down to the hardware's capabilities (according to the
265 * entries in the var structure). Return != 0 for invalid regno.
268 static int vfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
269 u_int transp
, struct fb_info
*info
)
271 if (regno
>= 256) /* no. of hw registers */
274 * Program hardware... do anything you want with transp
277 /* grayscale works only partially under directcolor */
278 if (info
->var
.grayscale
) {
279 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
281 (red
* 77 + green
* 151 + blue
* 28) >> 8;
285 * var->{color}.offset contains start of bitfield
286 * var->{color}.length contains length of bitfield
287 * {hardwarespecific} contains width of RAMDAC
288 * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
289 * RAMDAC[X] is programmed to (red, green, blue)
292 * var->{color}.offset is 0 unless the palette index takes less than
293 * bits_per_pixel bits and is stored in the upper
294 * bits of the pixel value
295 * var->{color}.length is set so that 1 << length is the number of available
298 * RAMDAC[X] is programmed to (red, green, blue)
301 * does not use DAC. Usually 3 are present.
302 * var->{color}.offset contains start of bitfield
303 * var->{color}.length contains length of bitfield
304 * cmap is programmed to (red << red.offset) | (green << green.offset) |
305 * (blue << blue.offset) | (transp << transp.offset)
306 * RAMDAC does not exist
308 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
309 switch (info
->fix
.visual
) {
310 case FB_VISUAL_TRUECOLOR
:
311 case FB_VISUAL_PSEUDOCOLOR
:
312 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
313 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
314 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
315 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
317 case FB_VISUAL_DIRECTCOLOR
:
318 red
= CNVT_TOHW(red
, 8); /* expect 8 bit DAC */
319 green
= CNVT_TOHW(green
, 8);
320 blue
= CNVT_TOHW(blue
, 8);
321 /* hey, there is bug in transp handling... */
322 transp
= CNVT_TOHW(transp
, 8);
326 /* Truecolor has hardware independent palette */
327 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
333 v
= (red
<< info
->var
.red
.offset
) |
334 (green
<< info
->var
.green
.offset
) |
335 (blue
<< info
->var
.blue
.offset
) |
336 (transp
<< info
->var
.transp
.offset
);
337 switch (info
->var
.bits_per_pixel
) {
341 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
345 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
354 * Pan or Wrap the Display
356 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
359 static int vfb_pan_display(struct fb_var_screeninfo
*var
,
360 struct fb_info
*info
)
362 if (var
->vmode
& FB_VMODE_YWRAP
) {
363 if (var
->yoffset
>= info
->var
.yres_virtual
||
367 if (var
->xoffset
+ info
->var
.xres
> info
->var
.xres_virtual
||
368 var
->yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
)
371 info
->var
.xoffset
= var
->xoffset
;
372 info
->var
.yoffset
= var
->yoffset
;
373 if (var
->vmode
& FB_VMODE_YWRAP
)
374 info
->var
.vmode
|= FB_VMODE_YWRAP
;
376 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
381 * Most drivers don't need their own mmap function
384 static int vfb_mmap(struct fb_info
*info
,
385 struct vm_area_struct
*vma
)
387 return remap_vmalloc_range(vma
, (void *)info
->fix
.smem_start
, vma
->vm_pgoff
);
392 * The virtual framebuffer driver is only enabled if explicitly
393 * requested by passing 'video=vfb:' (or any actual options).
395 static int __init
vfb_setup(char *options
)
409 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
412 /* Test disable for backwards compatibility */
413 if (!strcmp(this_opt
, "disable"))
416 mode_option
= this_opt
;
426 static int vfb_probe(struct platform_device
*dev
)
428 struct fb_info
*info
;
429 unsigned int size
= PAGE_ALIGN(videomemorysize
);
430 int retval
= -ENOMEM
;
433 * For real video cards we use ioremap.
435 if (!(videomemory
= vmalloc_32_user(size
)))
438 info
= framebuffer_alloc(sizeof(u32
) * 256, &dev
->dev
);
442 info
->screen_base
= (char __iomem
*)videomemory
;
443 info
->fbops
= &vfb_ops
;
445 if (!fb_find_mode(&info
->var
, info
, mode_option
,
446 NULL
, 0, &vfb_default
, 8)){
447 fb_err(info
, "Unable to find usable video mode.\n");
452 vfb_fix
.smem_start
= (unsigned long) videomemory
;
453 vfb_fix
.smem_len
= videomemorysize
;
455 info
->pseudo_palette
= info
->par
;
457 info
->flags
= FBINFO_FLAG_DEFAULT
;
459 retval
= fb_alloc_cmap(&info
->cmap
, 256, 0);
463 retval
= register_framebuffer(info
);
466 platform_set_drvdata(dev
, info
);
470 fb_info(info
, "Virtual frame buffer device, using %ldK of video memory\n",
471 videomemorysize
>> 10);
474 fb_dealloc_cmap(&info
->cmap
);
476 framebuffer_release(info
);
482 static int vfb_remove(struct platform_device
*dev
)
484 struct fb_info
*info
= platform_get_drvdata(dev
);
487 unregister_framebuffer(info
);
489 fb_dealloc_cmap(&info
->cmap
);
490 framebuffer_release(info
);
495 static struct platform_driver vfb_driver
= {
497 .remove
= vfb_remove
,
503 static struct platform_device
*vfb_device
;
505 static int __init
vfb_init(void)
512 if (fb_get_options("vfb", &option
))
520 ret
= platform_driver_register(&vfb_driver
);
523 vfb_device
= platform_device_alloc("vfb", 0);
526 ret
= platform_device_add(vfb_device
);
531 platform_device_put(vfb_device
);
532 platform_driver_unregister(&vfb_driver
);
539 module_init(vfb_init
);
542 static void __exit
vfb_exit(void)
544 platform_device_unregister(vfb_device
);
545 platform_driver_unregister(&vfb_driver
);
548 module_exit(vfb_exit
);
550 MODULE_LICENSE("GPL");