root/drivers/video/fbdev/vfb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_line_length
  2. vfb_check_var
  3. vfb_set_par
  4. vfb_setcolreg
  5. vfb_pan_display
  6. vfb_mmap
  7. vfb_setup
  8. vfb_probe
  9. vfb_remove
  10. vfb_init
  11. vfb_exit

   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 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,
  91         .fb_mmap        = vfb_mmap,
  92 };
  93 
  94     /*
  95      *  Internal routines
  96      */
  97 
  98 static u_long get_line_length(int xres_virtual, int bpp)
  99 {
 100         u_long length;
 101 
 102         length = xres_virtual * bpp;
 103         length = (length + 31) & ~31;
 104         length >>= 3;
 105         return (length);
 106 }
 107 
 108     /*
 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. 
 114      */
 115 
 116 static int vfb_check_var(struct fb_var_screeninfo *var,
 117                          struct fb_info *info)
 118 {
 119         u_long line_length;
 120 
 121         /*
 122          *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
 123          *  as FB_VMODE_SMOOTH_XPAN is only used internally
 124          */
 125 
 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;
 130         }
 131 
 132         /*
 133          *  Some very basic checks
 134          */
 135         if (!var->xres)
 136                 var->xres = 1;
 137         if (!var->yres)
 138                 var->yres = 1;
 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;
 153         else
 154                 return -EINVAL;
 155 
 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;
 160 
 161         /*
 162          *  Memory limit
 163          */
 164         line_length =
 165             get_line_length(var->xres_virtual, var->bits_per_pixel);
 166         if (line_length * var->yres_virtual > videomemorysize)
 167                 return -ENOMEM;
 168 
 169         /*
 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.
 173          */
 174         switch (var->bits_per_pixel) {
 175         case 1:
 176         case 8:
 177                 var->red.offset = 0;
 178                 var->red.length = 8;
 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;
 185                 break;
 186         case 16:                /* RGBA 5551 */
 187                 if (var->transp.length) {
 188                         var->red.offset = 0;
 189                         var->red.length = 5;
 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 */
 197                         var->red.offset = 0;
 198                         var->red.length = 5;
 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;
 205                 }
 206                 break;
 207         case 24:                /* RGB 888 */
 208                 var->red.offset = 0;
 209                 var->red.length = 8;
 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;
 216                 break;
 217         case 32:                /* RGBA 8888 */
 218                 var->red.offset = 0;
 219                 var->red.length = 8;
 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;
 226                 break;
 227         }
 228         var->red.msb_right = 0;
 229         var->green.msb_right = 0;
 230         var->blue.msb_right = 0;
 231         var->transp.msb_right = 0;
 232 
 233         return 0;
 234 }
 235 
 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. 
 239  */
 240 static int vfb_set_par(struct fb_info *info)
 241 {
 242         switch (info->var.bits_per_pixel) {
 243         case 1:
 244                 info->fix.visual = FB_VISUAL_MONO01;
 245                 break;
 246         case 8:
 247                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 248                 break;
 249         case 16:
 250         case 24:
 251         case 32:
 252                 info->fix.visual = FB_VISUAL_TRUECOLOR;
 253                 break;
 254         }
 255 
 256         info->fix.line_length = get_line_length(info->var.xres_virtual,
 257                                                 info->var.bits_per_pixel);
 258 
 259         return 0;
 260 }
 261 
 262     /*
 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.
 266      */
 267 
 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)
 270 {
 271         if (regno >= 256)       /* no. of hw registers */
 272                 return 1;
 273         /*
 274          * Program hardware... do anything you want with transp
 275          */
 276 
 277         /* grayscale works only partially under directcolor */
 278         if (info->var.grayscale) {
 279                 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
 280                 red = green = blue =
 281                     (red * 77 + green * 151 + blue * 28) >> 8;
 282         }
 283 
 284         /* Directcolor:
 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)
 290          *
 291          * Pseudocolor:
 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
 296          *                        palette entries
 297          *    cmap is not used
 298          *    RAMDAC[X] is programmed to (red, green, blue)
 299          *
 300          * Truecolor:
 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
 307          */
 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);
 316                 break;
 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);
 323                 break;
 324         }
 325 #undef CNVT_TOHW
 326         /* Truecolor has hardware independent palette */
 327         if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
 328                 u32 v;
 329 
 330                 if (regno >= 16)
 331                         return 1;
 332 
 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) {
 338                 case 8:
 339                         break;
 340                 case 16:
 341                         ((u32 *) (info->pseudo_palette))[regno] = v;
 342                         break;
 343                 case 24:
 344                 case 32:
 345                         ((u32 *) (info->pseudo_palette))[regno] = v;
 346                         break;
 347                 }
 348                 return 0;
 349         }
 350         return 0;
 351 }
 352 
 353     /*
 354      *  Pan or Wrap the Display
 355      *
 356      *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 357      */
 358 
 359 static int vfb_pan_display(struct fb_var_screeninfo *var,
 360                            struct fb_info *info)
 361 {
 362         if (var->vmode & FB_VMODE_YWRAP) {
 363                 if (var->yoffset >= info->var.yres_virtual ||
 364                     var->xoffset)
 365                         return -EINVAL;
 366         } else {
 367                 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
 368                     var->yoffset + info->var.yres > info->var.yres_virtual)
 369                         return -EINVAL;
 370         }
 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;
 375         else
 376                 info->var.vmode &= ~FB_VMODE_YWRAP;
 377         return 0;
 378 }
 379 
 380     /*
 381      *  Most drivers don't need their own mmap function 
 382      */
 383 
 384 static int vfb_mmap(struct fb_info *info,
 385                     struct vm_area_struct *vma)
 386 {
 387         return remap_vmalloc_range(vma, (void *)info->fix.smem_start, vma->vm_pgoff);
 388 }
 389 
 390 #ifndef MODULE
 391 /*
 392  * The virtual framebuffer driver is only enabled if explicitly
 393  * requested by passing 'video=vfb:' (or any actual options).
 394  */
 395 static int __init vfb_setup(char *options)
 396 {
 397         char *this_opt;
 398 
 399         vfb_enable = 0;
 400 
 401         if (!options)
 402                 return 1;
 403 
 404         vfb_enable = 1;
 405 
 406         if (!*options)
 407                 return 1;
 408 
 409         while ((this_opt = strsep(&options, ",")) != NULL) {
 410                 if (!*this_opt)
 411                         continue;
 412                 /* Test disable for backwards compatibility */
 413                 if (!strcmp(this_opt, "disable"))
 414                         vfb_enable = 0;
 415                 else
 416                         mode_option = this_opt;
 417         }
 418         return 1;
 419 }
 420 #endif  /*  MODULE  */
 421 
 422     /*
 423      *  Initialisation
 424      */
 425 
 426 static int vfb_probe(struct platform_device *dev)
 427 {
 428         struct fb_info *info;
 429         unsigned int size = PAGE_ALIGN(videomemorysize);
 430         int retval = -ENOMEM;
 431 
 432         /*
 433          * For real video cards we use ioremap.
 434          */
 435         if (!(videomemory = vmalloc_32_user(size)))
 436                 return retval;
 437 
 438         info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
 439         if (!info)
 440                 goto err;
 441 
 442         info->screen_base = (char __iomem *)videomemory;
 443         info->fbops = &vfb_ops;
 444 
 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");
 448                 retval = -EINVAL;
 449                 goto err1;
 450         }
 451 
 452         vfb_fix.smem_start = (unsigned long) videomemory;
 453         vfb_fix.smem_len = videomemorysize;
 454         info->fix = vfb_fix;
 455         info->pseudo_palette = info->par;
 456         info->par = NULL;
 457         info->flags = FBINFO_FLAG_DEFAULT;
 458 
 459         retval = fb_alloc_cmap(&info->cmap, 256, 0);
 460         if (retval < 0)
 461                 goto err1;
 462 
 463         retval = register_framebuffer(info);
 464         if (retval < 0)
 465                 goto err2;
 466         platform_set_drvdata(dev, info);
 467 
 468         vfb_set_par(info);
 469 
 470         fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n",
 471                 videomemorysize >> 10);
 472         return 0;
 473 err2:
 474         fb_dealloc_cmap(&info->cmap);
 475 err1:
 476         framebuffer_release(info);
 477 err:
 478         vfree(videomemory);
 479         return retval;
 480 }
 481 
 482 static int vfb_remove(struct platform_device *dev)
 483 {
 484         struct fb_info *info = platform_get_drvdata(dev);
 485 
 486         if (info) {
 487                 unregister_framebuffer(info);
 488                 vfree(videomemory);
 489                 fb_dealloc_cmap(&info->cmap);
 490                 framebuffer_release(info);
 491         }
 492         return 0;
 493 }
 494 
 495 static struct platform_driver vfb_driver = {
 496         .probe  = vfb_probe,
 497         .remove = vfb_remove,
 498         .driver = {
 499                 .name   = "vfb",
 500         },
 501 };
 502 
 503 static struct platform_device *vfb_device;
 504 
 505 static int __init vfb_init(void)
 506 {
 507         int ret = 0;
 508 
 509 #ifndef MODULE
 510         char *option = NULL;
 511 
 512         if (fb_get_options("vfb", &option))
 513                 return -ENODEV;
 514         vfb_setup(option);
 515 #endif
 516 
 517         if (!vfb_enable)
 518                 return -ENXIO;
 519 
 520         ret = platform_driver_register(&vfb_driver);
 521 
 522         if (!ret) {
 523                 vfb_device = platform_device_alloc("vfb", 0);
 524 
 525                 if (vfb_device)
 526                         ret = platform_device_add(vfb_device);
 527                 else
 528                         ret = -ENOMEM;
 529 
 530                 if (ret) {
 531                         platform_device_put(vfb_device);
 532                         platform_driver_unregister(&vfb_driver);
 533                 }
 534         }
 535 
 536         return ret;
 537 }
 538 
 539 module_init(vfb_init);
 540 
 541 #ifdef MODULE
 542 static void __exit vfb_exit(void)
 543 {
 544         platform_device_unregister(vfb_device);
 545         platform_driver_unregister(&vfb_driver);
 546 }
 547 
 548 module_exit(vfb_exit);
 549 
 550 MODULE_LICENSE("GPL");
 551 #endif                          /* MODULE */

/* [<][>][^][v][top][bottom][index][help] */