vfb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/video/vfb.c -- Virtual frame buffer device
  3.  *
  4.  * Copyright (C) 1997 Geert Uytterhoeven
  5.  *
  6.  *  This file is subject to the terms and conditions of the GNU General Public
  7.  *  License. See the file COPYING in the main directory of this archive for
  8.  *  more details.
  9.  */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/errno.h>
  13. #include <linux/string.h>
  14. #include <linux/mm.h>
  15. #include <linux/tty.h>
  16. #include <linux/slab.h>
  17. #include <linux/vmalloc.h>
  18. #include <linux/delay.h>
  19. #include <linux/interrupt.h>
  20. #include <asm/uaccess.h>
  21. #include <linux/fb.h>
  22. #include <linux/init.h>
  23. #include <video/fbcon.h>
  24. #include <video/fbcon-mfb.h>
  25. #include <video/fbcon-cfb2.h>
  26. #include <video/fbcon-cfb4.h>
  27. #include <video/fbcon-cfb8.h>
  28. #include <video/fbcon-cfb16.h>
  29. #include <video/fbcon-cfb24.h>
  30. #include <video/fbcon-cfb32.h>
  31.     /*
  32.      *  RAM we reserve for the frame buffer. This defines the maximum screen
  33.      *  size
  34.      *
  35.      *  The default can be overridden if the driver is compiled as a module
  36.      */
  37. #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */
  38. static u_long videomemory, videomemorysize = VIDEOMEMSIZE;
  39. MODULE_PARM(videomemorysize, "l");
  40. static int currcon = 0;
  41. static struct display disp;
  42. static struct fb_info fb_info;
  43. static struct { u_char red, green, blue, pad; } palette[256];
  44. static union {
  45. #ifdef FBCON_HAS_CFB16
  46.     u16 cfb16[16];
  47. #endif
  48. #ifdef FBCON_HAS_CFB24
  49.     u32 cfb24[16];
  50. #endif
  51. #ifdef FBCON_HAS_CFB32
  52.     u32 cfb32[16];
  53. #endif
  54. } fbcon_cmap;
  55. static char vfb_name[16] = "Virtual FB";
  56. static struct fb_var_screeninfo vfb_default = {
  57.     /* 640x480, 8 bpp */
  58.     640, 480, 640, 480, 0, 0, 8, 0,
  59.     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
  60.     0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2,
  61.     0, FB_VMODE_NONINTERLACED
  62. };
  63. static int vfb_enable = 0; /* disabled by default */
  64.     /*
  65.      *  Interface used by the world
  66.      */
  67. int vfb_setup(char*);
  68. static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
  69.        struct fb_info *info);
  70. static int vfb_get_var(struct fb_var_screeninfo *var, int con,
  71.        struct fb_info *info);
  72. static int vfb_set_var(struct fb_var_screeninfo *var, int con,
  73.        struct fb_info *info);
  74. static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
  75.    struct fb_info *info);
  76. static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  77. struct fb_info *info);
  78. static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  79. struct fb_info *info);
  80.     /*
  81.      *  Interface to the low level console driver
  82.      */
  83. int vfb_init(void);
  84. static int vfbcon_switch(int con, struct fb_info *info);
  85. static int vfbcon_updatevar(int con, struct fb_info *info);
  86. static void vfbcon_blank(int blank, struct fb_info *info);
  87.     /*
  88.      *  Internal routines
  89.      */
  90. static u_long get_line_length(int xres_virtual, int bpp);
  91. static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
  92.    struct fb_var_screeninfo *var);
  93. static void set_color_bitfields(struct fb_var_screeninfo *var);
  94. static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  95.                          u_int *transp, struct fb_info *info);
  96. static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  97.                          u_int transp, struct fb_info *info);
  98. static void do_install_cmap(int con, struct fb_info *info);
  99. static struct fb_ops vfb_ops = {
  100. owner: THIS_MODULE,
  101. fb_get_fix: vfb_get_fix,
  102. fb_get_var: vfb_get_var,
  103. fb_set_var: vfb_set_var,
  104. fb_get_cmap: vfb_get_cmap,
  105. fb_set_cmap: vfb_set_cmap,
  106. fb_pan_display: vfb_pan_display,
  107. };
  108.     /*
  109.      *  Get the Fixed Part of the Display
  110.      */
  111. static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
  112.        struct fb_info *info)
  113. {
  114.     struct fb_var_screeninfo *var;
  115.     if (con == -1)
  116. var = &vfb_default;
  117.     else
  118. var = &fb_display[con].var;
  119.     vfb_encode_fix(fix, var);
  120.     return 0;
  121. }
  122.     /*
  123.      *  Get the User Defined Part of the Display
  124.      */
  125. static int vfb_get_var(struct fb_var_screeninfo *var, int con,
  126.        struct fb_info *info)
  127. {
  128.     if (con == -1)
  129. *var = vfb_default;
  130.     else
  131. *var = fb_display[con].var;
  132.     set_color_bitfields(var);
  133.     return 0;
  134. }
  135.     /*
  136.      *  Set the User Defined Part of the Display
  137.      */
  138. static int vfb_set_var(struct fb_var_screeninfo *var, int con,
  139.        struct fb_info *info)
  140. {
  141.     int err, activate = var->activate;
  142.     int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
  143.     u_long line_length;
  144.     struct display *display;
  145.     if (con >= 0)
  146. display = &fb_display[con];
  147.     else
  148. display = &disp; /* used during initialization */
  149.     /*
  150.      *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
  151.      *  as FB_VMODE_SMOOTH_XPAN is only used internally
  152.      */
  153.     if (var->vmode & FB_VMODE_CONUPDATE) {
  154. var->vmode |= FB_VMODE_YWRAP;
  155. var->xoffset = display->var.xoffset;
  156. var->yoffset = display->var.yoffset;
  157.     }
  158.     /*
  159.      *  Some very basic checks
  160.      */
  161.     if (!var->xres)
  162. var->xres = 1;
  163.     if (!var->yres)
  164. var->yres = 1;
  165.     if (var->xres > var->xres_virtual)
  166. var->xres_virtual = var->xres;
  167.     if (var->yres > var->yres_virtual)
  168. var->yres_virtual = var->yres;
  169.     if (var->bits_per_pixel <= 1)
  170. var->bits_per_pixel = 1;
  171.     else if (var->bits_per_pixel <= 8)
  172. var->bits_per_pixel = 8;
  173.     else if (var->bits_per_pixel <= 16)
  174. var->bits_per_pixel = 16;
  175. #if 0
  176.     /* fbcon doesn't support this (yet) */
  177.     else if (var->bits_per_pixel <= 24)
  178. var->bits_per_pixel = 24;
  179.     else if (var->bits_per_pixel <= 32)
  180. var->bits_per_pixel = 32;
  181. #endif
  182.     else
  183. return -EINVAL;
  184.     /*
  185.      *  Memory limit
  186.      */
  187.     line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
  188.     if (line_length*var->yres_virtual > videomemorysize)
  189. return -ENOMEM;
  190.     set_color_bitfields(var);
  191.     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
  192. oldxres = display->var.xres;
  193. oldyres = display->var.yres;
  194. oldvxres = display->var.xres_virtual;
  195. oldvyres = display->var.yres_virtual;
  196. oldbpp = display->var.bits_per_pixel;
  197. display->var = *var;
  198. if (oldxres != var->xres || oldyres != var->yres ||
  199.     oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
  200.     oldbpp != var->bits_per_pixel) {
  201.     struct fb_fix_screeninfo fix;
  202.     vfb_encode_fix(&fix, var);
  203.     display->screen_base = (char *)videomemory;
  204.     display->visual = fix.visual;
  205.     display->type = fix.type;
  206.     display->type_aux = fix.type_aux;
  207.     display->ypanstep = fix.ypanstep;
  208.     display->ywrapstep = fix.ywrapstep;
  209.     display->line_length = fix.line_length;
  210.     display->can_soft_blank = 1;
  211.     display->inverse = 0;
  212.     switch (var->bits_per_pixel) {
  213. #ifdef FBCON_HAS_MFB
  214. case 1:
  215.     display->dispsw = &fbcon_mfb;
  216.     break;
  217. #endif
  218. #ifdef FBCON_HAS_CFB2
  219. case 2:
  220.     display->dispsw = &fbcon_cfb2;
  221.     break;
  222. #endif
  223. #ifdef FBCON_HAS_CFB4
  224. case 4:
  225.     display->dispsw = &fbcon_cfb4;
  226.     break;
  227. #endif
  228. #ifdef FBCON_HAS_CFB8
  229. case 8:
  230.     display->dispsw = &fbcon_cfb8;
  231.     break;
  232. #endif
  233. #ifdef FBCON_HAS_CFB16
  234. case 16:
  235.     display->dispsw = &fbcon_cfb16;
  236.     display->dispsw_data = fbcon_cmap.cfb16;
  237.     break;
  238. #endif
  239. #ifdef FBCON_HAS_CFB24
  240. case 24:
  241.     display->dispsw = &fbcon_cfb24;
  242.     display->dispsw_data = fbcon_cmap.cfb24;
  243.     break;
  244. #endif
  245. #ifdef FBCON_HAS_CFB32
  246. case 32:
  247.     display->dispsw = &fbcon_cfb32;
  248.     display->dispsw_data = fbcon_cmap.cfb32;
  249.     break;
  250. #endif
  251. default:
  252.     display->dispsw = &fbcon_dummy;
  253.     break;
  254.     }
  255.     if (fb_info.changevar)
  256. (*fb_info.changevar)(con);
  257. }
  258. if (oldbpp != var->bits_per_pixel) {
  259.     if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
  260. return err;
  261.     do_install_cmap(con, info);
  262. }
  263.     }
  264.     return 0;
  265. }
  266.     /*
  267.      *  Pan or Wrap the Display
  268.      *
  269.      *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
  270.      */
  271. static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
  272.    struct fb_info *info)
  273. {
  274.     if (var->vmode & FB_VMODE_YWRAP) {
  275. if (var->yoffset < 0 ||
  276.     var->yoffset >= fb_display[con].var.yres_virtual ||
  277.     var->xoffset)
  278.     return -EINVAL;
  279.     } else {
  280. if (var->xoffset+fb_display[con].var.xres >
  281.     fb_display[con].var.xres_virtual ||
  282.     var->yoffset+fb_display[con].var.yres >
  283.     fb_display[con].var.yres_virtual)
  284.     return -EINVAL;
  285.     }
  286.     fb_display[con].var.xoffset = var->xoffset;
  287.     fb_display[con].var.yoffset = var->yoffset;
  288.     if (var->vmode & FB_VMODE_YWRAP)
  289. fb_display[con].var.vmode |= FB_VMODE_YWRAP;
  290.     else
  291. fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
  292.     return 0;
  293. }
  294.     /*
  295.      *  Get the Colormap
  296.      */
  297. static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  298. struct fb_info *info)
  299. {
  300.     if (con == currcon) /* current console? */
  301. return fb_get_cmap(cmap, kspc, vfb_getcolreg, info);
  302.     else if (fb_display[con].cmap.len) /* non default colormap? */
  303. fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
  304.     else
  305. fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
  306.      cmap, kspc ? 0 : 2);
  307.     return 0;
  308. }
  309.     /*
  310.      *  Set the Colormap
  311.      */
  312. static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  313. struct fb_info *info)
  314. {
  315.     int err;
  316.     if (!fb_display[con].cmap.len) { /* no colormap allocated? */
  317. if ((err = fb_alloc_cmap(&fb_display[con].cmap,
  318.       1<<fb_display[con].var.bits_per_pixel, 0)))
  319.     return err;
  320.     }
  321.     if (con == currcon) /* current console? */
  322. return fb_set_cmap(cmap, kspc, vfb_setcolreg, info);
  323.     else
  324. fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
  325.     return 0;
  326. }
  327. int __init vfb_setup(char *options)
  328. {
  329.     char *this_opt;
  330.     fb_info.fontname[0] = '';
  331.     vfb_enable = 1;
  332.     if (!options || !*options)
  333. return 0;
  334.     while ((this_opt = strsep(&options, ",")) != NULL) {
  335. if (!strncmp(this_opt, "font:", 5))
  336.     strcpy(fb_info.fontname, this_opt+5);
  337.     }
  338.     return 0;
  339. }
  340.     /*
  341.      *  Initialisation
  342.      */
  343. int __init vfb_init(void)
  344. {
  345.     if (!vfb_enable)
  346. return -ENXIO;
  347.     if (!(videomemory = (u_long)vmalloc(videomemorysize)))
  348. return -ENOMEM;
  349.     strcpy(fb_info.modename, vfb_name);
  350.     fb_info.changevar = NULL;
  351.     fb_info.node = -1;
  352.     fb_info.fbops = &vfb_ops;
  353.     fb_info.disp = &disp;
  354.     fb_info.switch_con = &vfbcon_switch;
  355.     fb_info.updatevar = &vfbcon_updatevar;
  356.     fb_info.blank = &vfbcon_blank;
  357.     fb_info.flags = FBINFO_FLAG_DEFAULT;
  358.     vfb_set_var(&vfb_default, -1, &fb_info);
  359.     if (register_framebuffer(&fb_info) < 0) {
  360. vfree((void *)videomemory);
  361. return -EINVAL;
  362.     }
  363.     printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memoryn",
  364.    GET_FB_IDX(fb_info.node), videomemorysize>>10);
  365.     return 0;
  366. }
  367. static int vfbcon_switch(int con, struct fb_info *info)
  368. {
  369.     /* Do we have to save the colormap? */
  370.     if (fb_display[currcon].cmap.len)
  371. fb_get_cmap(&fb_display[currcon].cmap, 1, vfb_getcolreg, info);
  372.     currcon = con;
  373.     /* Install new colormap */
  374.     do_install_cmap(con, info);
  375.     return 0;
  376. }
  377.     /*
  378.      *  Update the `var' structure (called by fbcon.c)
  379.      */
  380. static int vfbcon_updatevar(int con, struct fb_info *info)
  381. {
  382.     /* Nothing */
  383.     return 0;
  384. }
  385.     /*
  386.      *  Blank the display.
  387.      */
  388. static void vfbcon_blank(int blank, struct fb_info *info)
  389. {
  390.     /* Nothing */
  391. }
  392. static u_long get_line_length(int xres_virtual, int bpp)
  393. {
  394.     u_long length;
  395.     
  396.     length = xres_virtual*bpp;
  397.     length = (length+31)&-32;
  398.     length >>= 3;
  399.     return(length);
  400. }
  401. static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
  402.    struct fb_var_screeninfo *var)
  403. {
  404.     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
  405.     strcpy(fix->id, vfb_name);
  406.     fix->smem_start = videomemory;
  407.     fix->smem_len = videomemorysize;
  408.     fix->type = FB_TYPE_PACKED_PIXELS;
  409.     fix->type_aux = 0;
  410.     switch (var->bits_per_pixel) {
  411. case 1:
  412.     fix->visual = FB_VISUAL_MONO01;
  413.     break;
  414. case 2:
  415. case 4:
  416. case 8:
  417.     fix->visual = FB_VISUAL_PSEUDOCOLOR;
  418.     break;
  419. case 16:
  420. case 24:
  421. case 32:
  422.     fix->visual = FB_VISUAL_TRUECOLOR;
  423.     break;
  424.     }
  425.     fix->ywrapstep = 1;
  426.     fix->xpanstep = 1;
  427.     fix->ypanstep = 1;
  428.     fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
  429. }
  430. static void set_color_bitfields(struct fb_var_screeninfo *var)
  431. {
  432.     switch (var->bits_per_pixel) {
  433. case 1:
  434. case 8:
  435.     var->red.offset = 0;
  436.     var->red.length = 8;
  437.     var->green.offset = 0;
  438.     var->green.length = 8;
  439.     var->blue.offset = 0;
  440.     var->blue.length = 8;
  441.     var->transp.offset = 0;
  442.     var->transp.length = 0;
  443.     break;
  444. case 16: /* RGB 565 */
  445.     var->red.offset = 0;
  446.     var->red.length = 5;
  447.     var->green.offset = 5;
  448.     var->green.length = 6;
  449.     var->blue.offset = 11;
  450.     var->blue.length = 5;
  451.     var->transp.offset = 0;
  452.     var->transp.length = 0;
  453.     break;
  454. case 24: /* RGB 888 */
  455.     var->red.offset = 0;
  456.     var->red.length = 8;
  457.     var->green.offset = 8;
  458.     var->green.length = 8;
  459.     var->blue.offset = 16;
  460.     var->blue.length = 8;
  461.     var->transp.offset = 0;
  462.     var->transp.length = 0;
  463.     break;
  464. case 32: /* RGBA 8888 */
  465.     var->red.offset = 0;
  466.     var->red.length = 8;
  467.     var->green.offset = 8;
  468.     var->green.length = 8;
  469.     var->blue.offset = 16;
  470.     var->blue.length = 8;
  471.     var->transp.offset = 24;
  472.     var->transp.length = 8;
  473.     break;
  474.     }
  475.     var->red.msb_right = 0;
  476.     var->green.msb_right = 0;
  477.     var->blue.msb_right = 0;
  478.     var->transp.msb_right = 0;
  479. }
  480.     /*
  481.      *  Read a single color register and split it into
  482.      *  colors/transparent. Return != 0 for invalid regno.
  483.      */
  484. static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  485.                          u_int *transp, struct fb_info *info)
  486. {
  487.     if (regno > 255)
  488. return 1;
  489.     *red = (palette[regno].red<<8) | palette[regno].red;
  490.     *green = (palette[regno].green<<8) | palette[regno].green;
  491.     *blue = (palette[regno].blue<<8) | palette[regno].blue;
  492.     *transp = 0;
  493.     return 0;
  494. }
  495.     /*
  496.      *  Set a single color register. The values supplied are already
  497.      *  rounded down to the hardware's capabilities (according to the
  498.      *  entries in the var structure). Return != 0 for invalid regno.
  499.      */
  500. static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  501.                          u_int transp, struct fb_info *info)
  502. {
  503.     if (regno > 255)
  504. return 1;
  505.     red >>= 8;
  506.     green >>= 8;
  507.     blue >>= 8;
  508.     palette[regno].red = red;
  509.     palette[regno].green = green;
  510.     palette[regno].blue = blue;
  511.     return 0;
  512. }
  513. static void do_install_cmap(int con, struct fb_info *info)
  514. {
  515.     if (con != currcon)
  516. return;
  517.     if (fb_display[con].cmap.len)
  518. fb_set_cmap(&fb_display[con].cmap, 1, vfb_setcolreg, info);
  519.     else
  520. fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
  521.     vfb_setcolreg, info);
  522. }
  523. #ifdef MODULE
  524. MODULE_LICENSE("GPL");
  525. int init_module(void)
  526. {
  527.     return vfb_init();
  528. }
  529. void cleanup_module(void)
  530. {
  531.     unregister_framebuffer(&fb_info);
  532.     vfree((void *)videomemory);
  533. }
  534. #endif /* MODULE */