1 /* 2 * linux/drivers/video/vfb.c -- Virtual frame buffer device 3 * 4 * Copyright (C) 2002 James Simmons 5 * 6 * Copyright (C) 1997 Geert Uytterhoeven 7 * 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 10 * more details. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/errno.h> 16 #include <linux/string.h> 17 #include <linux/mm.h> 18 #include <linux/vmalloc.h> 19 #include <linux/delay.h> 20 #include <linux/interrupt.h> 21 #include <linux/platform_device.h> 22 23 #include <linux/fb.h> 24 #include <linux/init.h> 25 26 /* 27 * RAM we reserve for the frame buffer. This defines the maximum screen 28 * size 29 * 30 * The default can be overridden if the driver is compiled as a module 31 */ 32 33 #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */ 34 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)"); 39 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)"); 43 44 static const struct fb_videomode vfb_default = { 45 .xres = 640, 46 .yres = 480, 47 .pixclock = 20000, 48 .left_margin = 64, 49 .right_margin = 64, 50 .upper_margin = 32, 51 .lower_margin = 32, 52 .hsync_len = 64, 53 .vsync_len = 2, 54 .vmode = FB_VMODE_NONINTERLACED, 55 }; 56 57 static struct fb_fix_screeninfo vfb_fix = { 58 .id = "Virtual FB", 59 .type = FB_TYPE_PACKED_PIXELS, 60 .visual = FB_VISUAL_PSEUDOCOLOR, 61 .xpanstep = 1, 62 .ypanstep = 1, 63 .ywrapstep = 1, 64 .accel = FB_ACCEL_NONE, 65 }; 66 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"); 70 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); 80 81 static void vfb_destroy(struct fb_info *info) 82 { 83 vfree(info->screen_buffer); 84 fb_dealloc_cmap(&info->cmap); 85 framebuffer_release(info); 86 } 87 88 static const struct fb_ops vfb_ops = { 89 .owner = THIS_MODULE, 90 __FB_DEFAULT_SYSMEM_OPS_RDWR, 91 .fb_check_var = vfb_check_var, 92 .fb_set_par = vfb_set_par, 93 .fb_setcolreg = vfb_setcolreg, 94 .fb_pan_display = vfb_pan_display, 95 __FB_DEFAULT_SYSMEM_OPS_DRAW, 96 .fb_mmap = vfb_mmap, 97 .fb_destroy = vfb_destroy, 98 }; 99 100 /* 101 * Internal routines 102 */ 103 104 static u_long get_line_length(int xres_virtual, int bpp) 105 { 106 u_long length; 107 108 length = xres_virtual * bpp; 109 length = (length + 31) & ~31; 110 length >>= 3; 111 return (length); 112 } 113 114 /* 115 * Setting the video mode has been split into two parts. 116 * First part, xxxfb_check_var, must not write anything 117 * to hardware, it should only verify and adjust var. 118 * This means it doesn't alter par but it does use hardware 119 * data from it to check this var. 120 */ 121 122 static int vfb_check_var(struct fb_var_screeninfo *var, 123 struct fb_info *info) 124 { 125 u_long line_length; 126 127 /* 128 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 129 * as FB_VMODE_SMOOTH_XPAN is only used internally 130 */ 131 132 if (var->vmode & FB_VMODE_CONUPDATE) { 133 var->vmode |= FB_VMODE_YWRAP; 134 var->xoffset = info->var.xoffset; 135 var->yoffset = info->var.yoffset; 136 } 137 138 /* 139 * Some very basic checks 140 */ 141 if (!var->xres) 142 var->xres = 1; 143 if (!var->yres) 144 var->yres = 1; 145 if (var->xres > var->xres_virtual) 146 var->xres_virtual = var->xres; 147 if (var->yres > var->yres_virtual) 148 var->yres_virtual = var->yres; 149 if (var->bits_per_pixel <= 1) 150 var->bits_per_pixel = 1; 151 else if (var->bits_per_pixel <= 8) 152 var->bits_per_pixel = 8; 153 else if (var->bits_per_pixel <= 16) 154 var->bits_per_pixel = 16; 155 else if (var->bits_per_pixel <= 24) 156 var->bits_per_pixel = 24; 157 else if (var->bits_per_pixel <= 32) 158 var->bits_per_pixel = 32; 159 else 160 return -EINVAL; 161 162 if (var->xres_virtual < var->xoffset + var->xres) 163 var->xres_virtual = var->xoffset + var->xres; 164 if (var->yres_virtual < var->yoffset + var->yres) 165 var->yres_virtual = var->yoffset + var->yres; 166 167 /* 168 * Memory limit 169 */ 170 line_length = 171 get_line_length(var->xres_virtual, var->bits_per_pixel); 172 if (line_length * var->yres_virtual > videomemorysize) 173 return -ENOMEM; 174 175 /* 176 * Now that we checked it we alter var. The reason being is that the video 177 * mode passed in might not work but slight changes to it might make it 178 * work. This way we let the user know what is acceptable. 179 */ 180 switch (var->bits_per_pixel) { 181 case 1: 182 case 8: 183 var->red.offset = 0; 184 var->red.length = 8; 185 var->green.offset = 0; 186 var->green.length = 8; 187 var->blue.offset = 0; 188 var->blue.length = 8; 189 var->transp.offset = 0; 190 var->transp.length = 0; 191 break; 192 case 16: /* RGBA 5551 */ 193 if (var->transp.length) { 194 var->red.offset = 0; 195 var->red.length = 5; 196 var->green.offset = 5; 197 var->green.length = 5; 198 var->blue.offset = 10; 199 var->blue.length = 5; 200 var->transp.offset = 15; 201 var->transp.length = 1; 202 } else { /* RGB 565 */ 203 var->red.offset = 0; 204 var->red.length = 5; 205 var->green.offset = 5; 206 var->green.length = 6; 207 var->blue.offset = 11; 208 var->blue.length = 5; 209 var->transp.offset = 0; 210 var->transp.length = 0; 211 } 212 break; 213 case 24: /* RGB 888 */ 214 var->red.offset = 0; 215 var->red.length = 8; 216 var->green.offset = 8; 217 var->green.length = 8; 218 var->blue.offset = 16; 219 var->blue.length = 8; 220 var->transp.offset = 0; 221 var->transp.length = 0; 222 break; 223 case 32: /* RGBA 8888 */ 224 var->red.offset = 0; 225 var->red.length = 8; 226 var->green.offset = 8; 227 var->green.length = 8; 228 var->blue.offset = 16; 229 var->blue.length = 8; 230 var->transp.offset = 24; 231 var->transp.length = 8; 232 break; 233 } 234 var->red.msb_right = 0; 235 var->green.msb_right = 0; 236 var->blue.msb_right = 0; 237 var->transp.msb_right = 0; 238 239 return 0; 240 } 241 242 /* This routine actually sets the video mode. It's in here where we 243 * the hardware state info->par and fix which can be affected by the 244 * change in par. For this driver it doesn't do much. 245 */ 246 static int vfb_set_par(struct fb_info *info) 247 { 248 switch (info->var.bits_per_pixel) { 249 case 1: 250 info->fix.visual = FB_VISUAL_MONO01; 251 break; 252 case 8: 253 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 254 break; 255 case 16: 256 case 24: 257 case 32: 258 info->fix.visual = FB_VISUAL_TRUECOLOR; 259 break; 260 } 261 262 info->fix.line_length = get_line_length(info->var.xres_virtual, 263 info->var.bits_per_pixel); 264 265 return 0; 266 } 267 268 /* 269 * Set a single color register. The values supplied are already 270 * rounded down to the hardware's capabilities (according to the 271 * entries in the var structure). Return != 0 for invalid regno. 272 */ 273 274 static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 275 u_int transp, struct fb_info *info) 276 { 277 if (regno >= 256) /* no. of hw registers */ 278 return 1; 279 /* 280 * Program hardware... do anything you want with transp 281 */ 282 283 /* grayscale works only partially under directcolor */ 284 if (info->var.grayscale) { 285 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 286 red = green = blue = 287 (red * 77 + green * 151 + blue * 28) >> 8; 288 } 289 290 /* Directcolor: 291 * var->{color}.offset contains start of bitfield 292 * var->{color}.length contains length of bitfield 293 * {hardwarespecific} contains width of RAMDAC 294 * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) 295 * RAMDAC[X] is programmed to (red, green, blue) 296 * 297 * Pseudocolor: 298 * var->{color}.offset is 0 unless the palette index takes less than 299 * bits_per_pixel bits and is stored in the upper 300 * bits of the pixel value 301 * var->{color}.length is set so that 1 << length is the number of available 302 * palette entries 303 * cmap is not used 304 * RAMDAC[X] is programmed to (red, green, blue) 305 * 306 * Truecolor: 307 * does not use DAC. Usually 3 are present. 308 * var->{color}.offset contains start of bitfield 309 * var->{color}.length contains length of bitfield 310 * cmap is programmed to (red << red.offset) | (green << green.offset) | 311 * (blue << blue.offset) | (transp << transp.offset) 312 * RAMDAC does not exist 313 */ 314 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 315 switch (info->fix.visual) { 316 case FB_VISUAL_TRUECOLOR: 317 case FB_VISUAL_PSEUDOCOLOR: 318 red = CNVT_TOHW(red, info->var.red.length); 319 green = CNVT_TOHW(green, info->var.green.length); 320 blue = CNVT_TOHW(blue, info->var.blue.length); 321 transp = CNVT_TOHW(transp, info->var.transp.length); 322 break; 323 case FB_VISUAL_DIRECTCOLOR: 324 red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ 325 green = CNVT_TOHW(green, 8); 326 blue = CNVT_TOHW(blue, 8); 327 /* hey, there is bug in transp handling... */ 328 transp = CNVT_TOHW(transp, 8); 329 break; 330 } 331 #undef CNVT_TOHW 332 /* Truecolor has hardware independent palette */ 333 if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 334 u32 v; 335 336 if (regno >= 16) 337 return 1; 338 339 v = (red << info->var.red.offset) | 340 (green << info->var.green.offset) | 341 (blue << info->var.blue.offset) | 342 (transp << info->var.transp.offset); 343 switch (info->var.bits_per_pixel) { 344 case 8: 345 break; 346 case 16: 347 ((u32 *) (info->pseudo_palette))[regno] = v; 348 break; 349 case 24: 350 case 32: 351 ((u32 *) (info->pseudo_palette))[regno] = v; 352 break; 353 } 354 return 0; 355 } 356 return 0; 357 } 358 359 /* 360 * Pan or Wrap the Display 361 * 362 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 363 */ 364 365 static int vfb_pan_display(struct fb_var_screeninfo *var, 366 struct fb_info *info) 367 { 368 if (var->vmode & FB_VMODE_YWRAP) { 369 if (var->yoffset >= info->var.yres_virtual || 370 var->xoffset) 371 return -EINVAL; 372 } else { 373 if (var->xoffset + info->var.xres > info->var.xres_virtual || 374 var->yoffset + info->var.yres > info->var.yres_virtual) 375 return -EINVAL; 376 } 377 info->var.xoffset = var->xoffset; 378 info->var.yoffset = var->yoffset; 379 if (var->vmode & FB_VMODE_YWRAP) 380 info->var.vmode |= FB_VMODE_YWRAP; 381 else 382 info->var.vmode &= ~FB_VMODE_YWRAP; 383 return 0; 384 } 385 386 /* 387 * Most drivers don't need their own mmap function 388 */ 389 390 static int vfb_mmap(struct fb_info *info, 391 struct vm_area_struct *vma) 392 { 393 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); 394 395 return remap_vmalloc_range(vma, (void *)info->fix.smem_start, vma->vm_pgoff); 396 } 397 398 #ifndef MODULE 399 /* 400 * The virtual framebuffer driver is only enabled if explicitly 401 * requested by passing 'video=vfb:' (or any actual options). 402 */ 403 static int __init vfb_setup(char *options) 404 { 405 char *this_opt; 406 407 vfb_enable = 0; 408 409 if (!options) 410 return 1; 411 412 vfb_enable = 1; 413 414 if (!*options) 415 return 1; 416 417 while ((this_opt = strsep(&options, ",")) != NULL) { 418 if (!*this_opt) 419 continue; 420 /* Test disable for backwards compatibility */ 421 if (!strcmp(this_opt, "disable")) 422 vfb_enable = 0; 423 else 424 mode_option = this_opt; 425 } 426 return 1; 427 } 428 #endif /* MODULE */ 429 430 /* 431 * Initialisation 432 */ 433 434 static int vfb_probe(struct platform_device *dev) 435 { 436 struct fb_info *info; 437 unsigned int size = PAGE_ALIGN(videomemorysize); 438 int retval = -ENOMEM; 439 440 /* 441 * For real video cards we use ioremap. 442 */ 443 if (!(videomemory = vmalloc_32_user(size))) 444 return retval; 445 446 info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); 447 if (!info) 448 goto err; 449 450 info->flags |= FBINFO_VIRTFB; 451 info->screen_buffer = videomemory; 452 info->fbops = &vfb_ops; 453 454 if (!fb_find_mode(&info->var, info, mode_option, 455 NULL, 0, &vfb_default, 8)){ 456 fb_err(info, "Unable to find usable video mode.\n"); 457 retval = -EINVAL; 458 goto err1; 459 } 460 461 vfb_fix.smem_start = (unsigned long) videomemory; 462 vfb_fix.smem_len = videomemorysize; 463 info->fix = vfb_fix; 464 info->pseudo_palette = info->par; 465 info->par = NULL; 466 467 retval = fb_alloc_cmap(&info->cmap, 256, 0); 468 if (retval < 0) 469 goto err1; 470 471 retval = register_framebuffer(info); 472 if (retval < 0) 473 goto err2; 474 platform_set_drvdata(dev, info); 475 476 vfb_set_par(info); 477 478 fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n", 479 videomemorysize >> 10); 480 return 0; 481 err2: 482 fb_dealloc_cmap(&info->cmap); 483 err1: 484 framebuffer_release(info); 485 err: 486 vfree(videomemory); 487 return retval; 488 } 489 490 static void vfb_remove(struct platform_device *dev) 491 { 492 struct fb_info *info = platform_get_drvdata(dev); 493 494 if (info) { 495 unregister_framebuffer(info); 496 } 497 } 498 499 static struct platform_driver vfb_driver = { 500 .probe = vfb_probe, 501 .remove = vfb_remove, 502 .driver = { 503 .name = "vfb", 504 }, 505 }; 506 507 static struct platform_device *vfb_device; 508 509 static int __init vfb_init(void) 510 { 511 int ret = 0; 512 513 #ifndef MODULE 514 char *option = NULL; 515 516 if (fb_get_options("vfb", &option)) 517 return -ENODEV; 518 vfb_setup(option); 519 #endif 520 521 if (!vfb_enable) 522 return -ENXIO; 523 524 ret = platform_driver_register(&vfb_driver); 525 526 if (!ret) { 527 vfb_device = platform_device_alloc("vfb", 0); 528 529 if (vfb_device) 530 ret = platform_device_add(vfb_device); 531 else 532 ret = -ENOMEM; 533 534 if (ret) { 535 platform_device_put(vfb_device); 536 platform_driver_unregister(&vfb_driver); 537 } 538 } 539 540 return ret; 541 } 542 543 module_init(vfb_init); 544 545 #ifdef MODULE 546 static void __exit vfb_exit(void) 547 { 548 platform_device_unregister(vfb_device); 549 platform_driver_unregister(&vfb_driver); 550 } 551 552 module_exit(vfb_exit); 553 554 MODULE_DESCRIPTION("Virtual Frame Buffer driver"); 555 MODULE_LICENSE("GPL"); 556 #endif /* MODULE */ 557