[PATCH] updated vfb.c

From: James Simmons (jsimmons@acsu.buffalo.edu)
Date: Wed Feb 09 2000 - 09:03:39 EST


Howdy!!!

   I updated the patch again. Its against a 2.3.43-4 kernel. It compiles
but I need to solve one more issue before I offically release it. That is
I use vmalloc which allocates virtual memory for the driver. What I want
to do is allocate a chunk of physical memory. I could use kmalloc but I'm
limited to 128K of memory. I could use bootmem but that seems to be good
only at boot time thus it couldn't be a module. Am I wrong here? I need
to also show a good example of the use of par. All fbdev driver writers
please read the text in vfb.c after appling the patch. It represents the
ideas where fbcon is heading in terms of future API. Please take advantage
of the var and fix fields inside fb_info. This patch also adds a fbcmap
field to fb_info.

Codito, ergo sum - "I code, therefore I am"
James Simmons (o_
fbdev/gfx developer (o_ (o_ //\
http://www.linux-fbdev.org (/)_ (/)_ V_/_
http://linuxgfx.sourceforge.net

diff -urN linux-2.3.43-4/drivers/video/vfb.c linux/drivers/video/vfb.c
--- linux-2.3.43-4/drivers/video/vfb.c Wed Nov 10 15:09:56 1999
+++ linux/drivers/video/vfb.c Wed Feb 9 08:26:08 2000
@@ -1,8 +1,40 @@
 /*
  * linux/drivers/video/vfb.c -- Virtual frame buffer device
  *
+ * Copyright (C) 1999 James Simmons
+ *
  * Copyright (C) 1997 Geert Uytterhoeven
  *
+ * I have started rewriting this driver as a example of the upcoming new API
+ * The primary goal is to remove the console code from fbdev and place it
+ * into fbcon.c. This reduces the code and makes writing a new fbdev driver
+ * easy since the author doesn't need to worry about console internals.
+ *
+ * First the roles of struct fb_info and struct display have changed. For
+ * each framebuffer device you can allocate a set of virtual terminals to
+ * it. Only one virtual terminal can be active per framebuffer device.
+ * So I have struct fb_info represent the current hardware state of the
+ * framebuffer. Meaning the resolution of the active VT (the one you're
+ * looking at) and other data is stored in the fb_info struct. When you VT
+ * switch the current video state then is stored into struct display for that
+ * terminal you just switched away from. Then the current video state is set
+ * to the data values stored in struct display for the VT you are switching
+ * too. As you can see doing this makes the con parameter pretty much useless
+ * for the fb_ops functions. As it should be. Since struct display is used to
+ * represent the video state of the hardware, for each terminal it also
+ * represents the extra parameters for a framebuffer device to act as a
+ * console terminal. In the future these parameters will be handled inside
+ * of fbcon.c so they will be of no concern to the driver writer.
+ *
+ * Also having fb_var_screeninfo and other data in fb_info pretty much
+ * eliminates the need for get_fix and get_var. Once all drivers use the
+ * fix, var, and cmap field fbcon can be written around these fields. This
+ * will also eliminate the need to regenerate fb_var_screeninfo and
+ * fb_fix_screeninfo data every time the get_var and get_fix functions are
+ * called as many drivers do now. The fb_var_screeninfo and
+ * fb_fix_screeninfo field in fb_info can be generated just in set_var and
+ * placed into struct fb_info.
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License. See the file COPYING in the main directory of this archive for
  * more details.
@@ -44,12 +76,11 @@
 
 #define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */
 
-static u_long videomemory, videomemorysize = VIDEOMEMSIZE;
+static void* videomemory;
+static u_long videomemorysize = VIDEOMEMSIZE;
 MODULE_PARM(videomemorysize, "l");
-static int currcon = 0;
 static struct display disp;
 static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
 static union {
 #ifdef FBCON_HAS_CFB16
     u16 cfb16[16];
@@ -61,7 +92,6 @@
     u32 cfb32[16];
 #endif
 } fbcon_cmap;
-static char vfb_name[16] = "Virtual FB";
 
 static struct fb_var_screeninfo vfb_default = {
     /* 640x480, 8 bpp */
@@ -71,13 +101,18 @@
     0, FB_VMODE_NONINTERLACED
 };
 
-static int vfb_enable = 0; /* disabled by default */
+static struct fb_fix_screeninfo vfb_fix = {
+ "Virtual FB", (unsigned long) NULL, 0, FB_TYPE_PACKED_PIXELS, 0,
+ FB_VISUAL_PSEUDOCOLOR, 1, 1, 1, 0, (unsigned long) NULL, 0, FB_ACCEL_NONE
+};
 
+static int vfb_enable = 0; /* disabled by default */
+MODULE_PARM(vfb_enable, "i");
 
     /*
      * Interface used by the world
      */
-
+int vfb_init(void);
 int vfb_setup(char*);
 
 static int vfb_open(struct fb_info *info, int user);
@@ -102,26 +137,19 @@
      * Interface to the low level console driver
      */
 
-int vfb_init(void);
 static int vfbcon_switch(int con, struct fb_info *info);
 static int vfbcon_updatevar(int con, struct fb_info *info);
 static void vfbcon_blank(int blank, struct fb_info *info);
 
-
     /*
      * Internal routines
      */
 
 static u_long get_line_length(int xres_virtual, int bpp);
-static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
- struct fb_var_screeninfo *var);
-static void set_color_bitfields(struct fb_var_screeninfo *var);
 static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                          u_int *transp, struct fb_info *info);
 static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                          u_int transp, struct fb_info *info);
-static void do_install_cmap(int con, struct fb_info *info);
-
 
 static struct fb_ops vfb_ops = {
     vfb_open, vfb_release, vfb_get_fix, vfb_get_var, vfb_set_var, vfb_get_cmap,
@@ -157,13 +185,7 @@
 static int vfb_get_fix(struct fb_fix_screeninfo *fix, int con,
                        struct fb_info *info)
 {
- struct fb_var_screeninfo *var;
-
- if (con == -1)
- var = &vfb_default;
- else
- var = &fb_display[con].var;
- vfb_encode_fix(fix, var);
+ *fix = info->fix;
     return 0;
 }
 
@@ -175,31 +197,38 @@
 static int vfb_get_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info)
 {
- if (con == -1)
- *var = vfb_default;
- else
- *var = fb_display[con].var;
- set_color_bitfields(var);
+ *var = info->var;
     return 0;
 }
 
 
     /*
      * Set the User Defined Part of the Display
+ *
+ * Note: This function should be split into two parts.
+ * First part, before "here hardware starts" comment,
+ * must not write anything to hardware, it should only
+ * verify and adjust var.
+ * Second part, after "here hardware starts" comment,
+ * should initialize hardware.
+ * *_switch code should call only second part, as
+ * videomode was already validated.
+ * When this function is invoked from *_switch, it
+ * should not return error, it should switch into
+ * dummycon instead of that.
      */
 
 static int vfb_set_var(struct fb_var_screeninfo *var, int con,
                        struct fb_info *info)
 {
     int err, activate = var->activate;
- int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
     u_long line_length;
+ struct display *display;
 
- struct display *display;
- if (con >= 0)
- display = &fb_display[con];
+ if (con < 0)
+ display = info->disp;
     else
- display = &disp; /* used during initialization */
+ display = fb_display + con;
 
     /*
      * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
@@ -208,8 +237,8 @@
 
     if (var->vmode & FB_VMODE_CONUPDATE) {
         var->vmode |= FB_VMODE_YWRAP;
- var->xoffset = display->var.xoffset;
- var->yoffset = display->var.yoffset;
+ var->xoffset = info->var.xoffset;
+ var->yoffset = info->var.yoffset;
     }
 
     /*
@@ -229,16 +258,18 @@
         var->bits_per_pixel = 8;
     else if (var->bits_per_pixel <= 16)
         var->bits_per_pixel = 16;
-#if 0
- /* fbcon doesn't support this (yet) */
     else if (var->bits_per_pixel <= 24)
         var->bits_per_pixel = 24;
     else if (var->bits_per_pixel <= 32)
         var->bits_per_pixel = 32;
-#endif
     else
         return -EINVAL;
 
+ if (var->xoffset > var->xres_virtual - var->xres)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yoffset > var->yres_virtual - var->yres)
+ var->yoffset = var->yres_virtual - var->yres;
+
     /*
      * Memory limit
      */
@@ -246,65 +277,115 @@
     if (line_length*var->yres_virtual > videomemorysize)
         return -ENOMEM;
 
- set_color_bitfields(var);
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 16: /* RGBA 5551 */
+ if (var->transp.length) {
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 10;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ } else { /* RGB 565 */
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 11;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 24: /* RGB 888 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 32: /* RGBA 8888 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
 
     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = display->var.xres;
- oldyres = display->var.yres;
- oldvxres = display->var.xres_virtual;
- oldvyres = display->var.yres_virtual;
- oldbpp = display->var.bits_per_pixel;
- display->var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- struct fb_fix_screeninfo fix;
-
- vfb_encode_fix(&fix, var);
- display->screen_base = (char *)videomemory;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->can_soft_blank = 1;
- display->inverse = 0;
+ if (info->var.xres != var->xres || info->var.yres != var->yres ||
+ info->var.xres_virtual != var->xres_virtual ||
+ info->var.yres_virtual != var->yres_virtual ||
+ info->var.bits_per_pixel != var->bits_per_pixel) {
+ /* Set the video mode. For a real video card we would fill in
+ * fb_info->par which is the hardware dependent structure.
+ */
             switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_MFB
                 case 1:
+ info->fix.visual = FB_VISUAL_MONO01;
                     display->dispsw = &fbcon_mfb;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB2
                 case 2:
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
                     display->dispsw = &fbcon_cfb2;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB4
                 case 4:
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
                     display->dispsw = &fbcon_cfb4;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB8
                 case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
                     display->dispsw = &fbcon_cfb8;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB16
                 case 16:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
                     display->dispsw = &fbcon_cfb16;
                     display->dispsw_data = fbcon_cmap.cfb16;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB24
                 case 24:
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
                     display->dispsw = &fbcon_cfb24;
                     display->dispsw_data = fbcon_cmap.cfb24;
                     break;
 #endif
 #ifdef FBCON_HAS_CFB32
                 case 32:
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
                     display->dispsw = &fbcon_cfb32;
                     display->dispsw_data = fbcon_cmap.cfb32;
                     break;
@@ -313,13 +394,25 @@
                     display->dispsw = &fbcon_dummy;
                     break;
             }
+ info->fix.line_length = get_line_length(var->xres_virtual,
+ var->bits_per_pixel);
+ info->var = *var;
+
+ display->visual = info->fix.visual;
+ display->type = info->fix.type;
+ display->type_aux = info->fix.type_aux;
+ display->ypanstep = info->fix.ypanstep;
+ display->ywrapstep = info->fix.ywrapstep;
+ display->line_length = info->fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+
             if (fb_info.changevar)
                 (*fb_info.changevar)(con);
         }
- if (oldbpp != var->bits_per_pixel) {
- if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+ if (info->var.bits_per_pixel != var->bits_per_pixel) {
+ if ((err = fb_set_cmap(&info->cmap, 1, vfb_setcolreg, info)))
                 return err;
- do_install_cmap(con, info);
         }
     }
     return 0;
@@ -336,23 +429,20 @@
                            struct fb_info *info)
 {
     if (var->vmode & FB_VMODE_YWRAP) {
- if (var->yoffset < 0 ||
- var->yoffset >= fb_display[con].var.yres_virtual ||
+ if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual ||
             var->xoffset)
             return -EINVAL;
     } else {
- if (var->xoffset+fb_display[con].var.xres >
- fb_display[con].var.xres_virtual ||
- var->yoffset+fb_display[con].var.yres >
- fb_display[con].var.yres_virtual)
- return -EINVAL;
+ if (var->xoffset + var->xres > info->var.xres_virtual ||
+ var->yoffset + var->yres > info->var.yres_virtual)
+ return -EINVAL;
     }
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
     if (var->vmode & FB_VMODE_YWRAP)
- fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+ info->var.vmode |= FB_VMODE_YWRAP;
     else
- fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+ info->var.vmode &= ~FB_VMODE_YWRAP;
     return 0;
 }
 
@@ -363,13 +453,7 @@
 static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
                         struct fb_info *info)
 {
- if (con == currcon) /* current console? */
- return fb_get_cmap(cmap, kspc, vfb_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
+ *cmap = info->cmap;
     return 0;
 }
 
@@ -380,18 +464,7 @@
 static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                         struct fb_info *info)
 {
- int err;
-
- if (!fb_display[con].cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap,
- 1<<fb_display[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console? */
- return fb_set_cmap(cmap, kspc, vfb_setcolreg, info);
- else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
+ return fb_set_cmap(cmap, kspc, vfb_setcolreg, info);
 }
 
 
@@ -425,7 +498,6 @@
     return 0;
 }
 
-
     /*
      * Initialisation
      */
@@ -435,41 +507,68 @@
     if (!vfb_enable)
         return -ENXIO;
 
- if (!(videomemory = (u_long)vmalloc(videomemorysize)))
+ /*
+ * For real video cards we use ioremap.
+ */
+ if (!(videomemory = vmalloc(videomemorysize)))
         return -ENOMEM;
 
- strcpy(fb_info.modename, vfb_name);
+ /*
+ * VFB must clear memory to prevent kernel info
+ * leakage into userspace
+ * VGA-based drivers MUST NOT clear memory if
+ * they want to be able to take over vgacon
+ */
+ memset(videomemory, 0, videomemorysize);
+
+ fb_info.disp->screen_base = videomemory;
+ /*
+ vfb_fix.smem_start = videomemory;
+ vfb_fix.smem_len = videomemorysize;
+ */
+ strcpy(fb_info.modename, vfb_fix.id);
     fb_info.changevar = NULL;
     fb_info.node = -1;
     fb_info.fbops = &vfb_ops;
+ fb_info.var = vfb_default;
+ fb_info.fix = vfb_fix;
     fb_info.disp = &disp;
     fb_info.switch_con = &vfbcon_switch;
     fb_info.updatevar = &vfbcon_updatevar;
     fb_info.blank = &vfbcon_blank;
     fb_info.flags = FBINFO_FLAG_DEFAULT;
-
- vfb_set_var(&vfb_default, -1, &fb_info);
+
+ /* Alloc but do not set the default color map */
+ fb_info.cmap.len = 1<<fb_info.var.bits_per_pixel;
+ fb_alloc_cmap(&fb_info.cmap, fb_info.cmap.len, 0);
 
     if (register_framebuffer(&fb_info) < 0) {
- vfree((void *)videomemory);
+ vfree(videomemory);
         return -EINVAL;
     }
 
- printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
- GET_FB_IDX(fb_info.node), videomemorysize>>10);
+ printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n", GET_FB_IDX(fb_info.node), videomemorysize>>10);
     return 0;
 }
 
-
 static int vfbcon_switch(int con, struct fb_info *info)
 {
- /* Do we have to save the colormap? */
- if (fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, vfb_getcolreg, info);
-
- currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
+ /* Save the colormap and video mode */
+ fb_copy_cmap(&info->cmap, &fb_display[last_console].cmap, 0);
+
+ memcpy(&fb_display[last_console].var, &info->var,
+ sizeof(struct fb_var_screeninfo));
+
+ /* Install a new colormap and change the video mode. By default fbcon
+ * sets all the colormaps and video modes to the default values at
+ * bootup.
+ */
+ fb_copy_cmap(&fb_display[con].cmap, &info->cmap, 0);
+ fb_set_cmap(&info->cmap, 1, vfb_setcolreg, info);
+
+ memcpy(&info->var, &fb_display[con].var,
+ sizeof(struct fb_var_screeninfo));
+ vfb_set_var(&info->var, con, &fb_info);
     return 0;
 }
 
@@ -479,7 +578,14 @@
 
 static int vfbcon_updatevar(int con, struct fb_info *info)
 {
- /* Nothing */
+ /* If you have hardware and you support xoffset/yoffset, you have
+ * to reprogram panning hardware */
+ int err;
+
+ if (info->fbops->fb_pan_display) {
+ if ((err = info->fbops->fb_pan_display(&fb_display[con].var,con,info)))
+ return err;
+ }
     return 0;
 }
 
@@ -496,112 +602,22 @@
 {
     u_long length;
     
- length = (xres_virtual+bpp-1)/bpp;
- length = (length+31)&-32;
+ length = xres_virtual * bpp;
+ length = (length+31)&~31;
     length >>= 3;
     return(length);
 }
-
-static void vfb_encode_fix(struct fb_fix_screeninfo *fix,
- struct fb_var_screeninfo *var)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, vfb_name);
- fix->smem_start = videomemory;
- fix->smem_len = videomemorysize;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- switch (var->bits_per_pixel) {
- case 1:
- fix->visual = FB_VISUAL_MONO01;
- break;
- case 2:
- case 4:
- case 8:
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- break;
- case 16:
- case 24:
- case 32:
- fix->visual = FB_VISUAL_TRUECOLOR;
- break;
- }
- fix->ywrapstep = 1;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
-}
-
-static void set_color_bitfields(struct fb_var_screeninfo *var)
-{
- switch (var->bits_per_pixel) {
- case 1:
- case 8:
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 16: /* RGB 565 */
- var->red.offset = 0;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 11;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 24: /* RGB 888 */
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 16;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 32: /* RGBA 8888 */
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 16;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- }
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
-}
-
-
+
     /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
+ * Yet another function that has become useless with the new API.
      */
 
 static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
                          u_int *transp, struct fb_info *info)
 {
- if (regno > 255)
- return 1;
- *red = (palette[regno].red<<8) | palette[regno].red;
- *green = (palette[regno].green<<8) | palette[regno].green;
- *blue = (palette[regno].blue<<8) | palette[regno].blue;
- *transp = 0;
     return 0;
 }
 
-
     /*
      * Set a single color register. The values supplied are already
      * rounded down to the hardware's capabilities (according to the
@@ -613,28 +629,77 @@
 {
     if (regno > 255)
         return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
- return 0;
-}
-
 
-static void do_install_cmap(int con, struct fb_info *info)
-{
- if (con != currcon)
- return;
- if (fb_display[con].cmap.len)
- fb_set_cmap(&fb_display[con].cmap, 1, vfb_setcolreg, info);
- else
- fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
- vfb_setcolreg, info);
+ /* grayscale works only partially under directcolor */
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Directcolor:
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * {hardwarespecific} contains width of DAC
+ * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+ * DAC[X] is programmed to (red, green, blue)
+ *
+ * Pseudocolor:
+ * uses offset = 0 && length = DAC register width.
+ * var->{color}.offset is 0
+ * var->{color}.length contains widht of DAC
+ * cmap is not used
+ * DAC[X] is programmed to (red, green, blue)
+ * Truecolor:
+ * does not use DAC.
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * cmap is programmed to (red << red.offset) | (green << green.offset) |
+ * (blue << blue.offset) | (transp << transp.offset)
+ * DAC does not exist
+ */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+ break;
+ case FB_VISUAL_DIRECTCOLOR:
+ red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */
+ green = CNVT_TOHW(green, 8);
+ blue = CNVT_TOHW(blue, 8);
+ /* hey, there is bug in transp handling... */
+ transp = CNVT_TOHW(transp, 8);
+ break;
+ }
+#undef CNVT_TOHW
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return 1;
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+ if (info->var.bits_per_pixel == 16)
+ ((u16*)(info->disp->dispsw_data))[regno] = v;
+ else
+ ((u32*)(info->disp->dispsw_data))[regno] = v;
+ return 0;
+ }
+ if (regno >= 256) /* no. of hw registers */
+ return 1;
+ /*
+ * Program hardware... do anything you want with transp
+ */
+ return 0;
 }
 
-
 #ifdef MODULE
 int init_module(void)
 {
@@ -644,7 +709,7 @@
 void cleanup_module(void)
 {
     unregister_framebuffer(&fb_info);
- vfree((void *)videomemory);
+ vfree(videomemory);
 }
 
 #endif /* MODULE */
diff -urN linux-2.3.43-4/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.3.43-4/include/linux/fb.h Fri Jan 21 10:06:38 2000
+++ linux/include/linux/fb.h Tue Feb 8 22:30:05 2000
@@ -272,6 +272,7 @@
    struct fb_var_screeninfo var; /* Current var */
    struct fb_fix_screeninfo fix; /* Current fix */
    struct fb_monspecs monspecs; /* Current Monitor specs */
+ struct fb_cmap cmap; /* Current color map */
    struct fb_ops *fbops;
    char *screen_base; /* Virtual address */
    struct display *disp; /* initial display variable */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Feb 15 2000 - 21:00:15 EST