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