fbdev: move fbdev core files to separate directory
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Thu, 13 Feb 2014 14:24:55 +0000 (16:24 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Thu, 17 Apr 2014 05:10:19 +0000 (08:10 +0300)
Instead of having fbdev framework core files at the root fbdev
directory, mixed with random fbdev device drivers, move the fbdev core
files to a separate core directory. This makes it much clearer which of
the files are actually part of the fbdev framework, and which are part
of device drivers.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
41 files changed:
Documentation/DocBook/device-drivers.tmpl
drivers/video/fbdev/Makefile
drivers/video/fbdev/aty/mach64_cursor.c
drivers/video/fbdev/cfbcopyarea.c [deleted file]
drivers/video/fbdev/cfbfillrect.c [deleted file]
drivers/video/fbdev/cfbimgblt.c [deleted file]
drivers/video/fbdev/core/Makefile [new file with mode: 0644]
drivers/video/fbdev/core/cfbcopyarea.c [new file with mode: 0644]
drivers/video/fbdev/core/cfbfillrect.c [new file with mode: 0644]
drivers/video/fbdev/core/cfbimgblt.c [new file with mode: 0644]
drivers/video/fbdev/core/fb_ddc.c [new file with mode: 0644]
drivers/video/fbdev/core/fb_defio.c [new file with mode: 0644]
drivers/video/fbdev/core/fb_draw.h [new file with mode: 0644]
drivers/video/fbdev/core/fb_notify.c [new file with mode: 0644]
drivers/video/fbdev/core/fb_sys_fops.c [new file with mode: 0644]
drivers/video/fbdev/core/fbcmap.c [new file with mode: 0644]
drivers/video/fbdev/core/fbcvt.c [new file with mode: 0644]
drivers/video/fbdev/core/fbmem.c [new file with mode: 0644]
drivers/video/fbdev/core/fbmon.c [new file with mode: 0644]
drivers/video/fbdev/core/fbsysfs.c [new file with mode: 0644]
drivers/video/fbdev/core/modedb.c [new file with mode: 0644]
drivers/video/fbdev/core/svgalib.c [new file with mode: 0644]
drivers/video/fbdev/core/syscopyarea.c [new file with mode: 0644]
drivers/video/fbdev/core/sysfillrect.c [new file with mode: 0644]
drivers/video/fbdev/core/sysimgblt.c [new file with mode: 0644]
drivers/video/fbdev/fb_ddc.c [deleted file]
drivers/video/fbdev/fb_defio.c [deleted file]
drivers/video/fbdev/fb_draw.h [deleted file]
drivers/video/fbdev/fb_notify.c [deleted file]
drivers/video/fbdev/fb_sys_fops.c [deleted file]
drivers/video/fbdev/fbcmap.c [deleted file]
drivers/video/fbdev/fbcvt.c [deleted file]
drivers/video/fbdev/fbmem.c [deleted file]
drivers/video/fbdev/fbmon.c [deleted file]
drivers/video/fbdev/fbsysfs.c [deleted file]
drivers/video/fbdev/modedb.c [deleted file]
drivers/video/fbdev/svgalib.c [deleted file]
drivers/video/fbdev/syscopyarea.c [deleted file]
drivers/video/fbdev/sysfillrect.c [deleted file]
drivers/video/fbdev/sysimgblt.c [deleted file]
drivers/video/fbdev/wmt_ge_rops.c

index 4d1aa8b44be766aff7679dc811fe85f557c3211a..cc63f30de166501e37f4ec4a707dc3ad5a0c371e 100644 (file)
@@ -276,7 +276,7 @@ X!Isound/sound_firmware.c
      </para>
 
      <sect1><title>Frame Buffer Memory</title>
-!Edrivers/video/fbdev/fbmem.c
+!Edrivers/video/fbdev/core/fbmem.c
      </sect1>
 <!--
      <sect1><title>Frame Buffer Console</title>
@@ -284,7 +284,7 @@ X!Edrivers/video/console/fbcon.c
      </sect1>
 -->
      <sect1><title>Frame Buffer Colormap</title>
-!Edrivers/video/fbdev/fbcmap.c
+!Edrivers/video/fbdev/core/fbcmap.c
      </sect1>
 <!-- FIXME:
   drivers/video/fbgen.c has no docs, which stuffs up the sgml.  Comment
@@ -294,8 +294,8 @@ X!Idrivers/video/fbgen.c
      </sect1>
 KAO -->
      <sect1><title>Frame Buffer Video Mode Database</title>
-!Idrivers/video/fbdev/modedb.c
-!Edrivers/video/fbdev/modedb.c
+!Idrivers/video/fbdev/core/modedb.c
+!Edrivers/video/fbdev/core/modedb.c
      </sect1>
      <sect1><title>Frame Buffer Macintosh Video Mode Database</title>
 !Edrivers/video/fbdev/macmodes.c
index 8a79eec2113bd67ee1f2475266d9f7d0023eb017..0284f2a12538c30d906de8084a59903016bda9e4 100644 (file)
@@ -4,25 +4,11 @@
 
 # Each configuration option enables a list of files.
 
-obj-y                             += fb_notify.o
-obj-$(CONFIG_FB)                  += fb.o
-fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
-                                     modedb.o fbcvt.o
-fb-objs                           := $(fb-y)
+obj-y                          += core/
 
 obj-$(CONFIG_EXYNOS_VIDEO)     += exynos/
 
-obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
-obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
-obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
-obj-$(CONFIG_FB_SYS_FILLRECT)  += sysfillrect.o
-obj-$(CONFIG_FB_SYS_COPYAREA)  += syscopyarea.o
-obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
-obj-$(CONFIG_FB_SYS_FOPS)      += fb_sys_fops.o
-obj-$(CONFIG_FB_SVGALIB)       += svgalib.o
 obj-$(CONFIG_FB_MACMODES)      += macmodes.o
-obj-$(CONFIG_FB_DDC)           += fb_ddc.o
-obj-$(CONFIG_FB_DEFERRED_IO)   += fb_defio.o
 obj-$(CONFIG_FB_WMT_GE_ROPS)   += wmt_ge_rops.o
 
 # Hardware specific drivers go first
index 0fe02e22d9a436e46cbc46fc7053e5afa83e3b2d..2fa0317ab3c7d1a89c2cf0b91ee3ef047fe2e10e 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include "../fb_draw.h"
+#include "../core/fb_draw.h"
 
 #include <asm/io.h>
 
diff --git a/drivers/video/fbdev/cfbcopyarea.c b/drivers/video/fbdev/cfbcopyarea.c
deleted file mode 100644 (file)
index bcb5723..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- *  Generic function for frame buffer with packed pixels of any depth.
- *
- *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
- *
- *  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.
- *
- * NOTES:
- *
- *  This is for cfb packed pixels. Iplan and such are incorporated in the
- *  drivers that need them.
- *
- *  FIXME
- *
- *  Also need to add code to deal with cards endians that are different than
- *  the native cpu endians. I also need to deal with MSB position in the word.
- *
- *  The two functions or copying forward and backward could be split up like
- *  the ones for filling, i.e. in aligned and unaligned versions. This would
- *  help moving some redundant computations and branches out of the loop, too.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-#include <asm/io.h>
-#include "fb_draw.h"
-
-#if BITS_PER_LONG == 32
-#  define FB_WRITEL fb_writel
-#  define FB_READL  fb_readl
-#else
-#  define FB_WRITEL fb_writeq
-#  define FB_READL  fb_readq
-#endif
-
-    /*
-     *  Generic bitwise copy algorithm
-     */
-
-static void
-bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
-               const unsigned long __iomem *src, unsigned src_idx, int bits,
-               unsigned n, u32 bswapmask)
-{
-       unsigned long first, last;
-       int const shift = dst_idx-src_idx;
-
-#if 0
-       /*
-        * If you suspect bug in this function, compare it with this simple
-        * memmove implementation.
-        */
-       fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
-                  (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
-       return;
-#endif
-
-       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
-       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
-
-       if (!shift) {
-               // Same alignment for source and dest
-
-               if (dst_idx+n <= bits) {
-                       // Single word
-                       if (last)
-                               first &= last;
-                       FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
-               } else {
-                       // Multiple destination words
-
-                       // Leading bits
-                       if (first != ~0UL) {
-                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
-                               dst++;
-                               src++;
-                               n -= bits - dst_idx;
-                       }
-
-                       // Main chunk
-                       n /= bits;
-                       while (n >= 8) {
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               FB_WRITEL(FB_READL(src++), dst++);
-                               n -= 8;
-                       }
-                       while (n--)
-                               FB_WRITEL(FB_READL(src++), dst++);
-
-                       // Trailing bits
-                       if (last)
-                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
-               }
-       } else {
-               /* Different alignment for source and dest */
-               unsigned long d0, d1;
-               int m;
-
-               int const left = shift & (bits - 1);
-               int const right = -shift & (bits - 1);
-
-               if (dst_idx+n <= bits) {
-                       // Single destination word
-                       if (last)
-                               first &= last;
-                       d0 = FB_READL(src);
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       if (shift > 0) {
-                               // Single source word
-                               d0 <<= left;
-                       } else if (src_idx+n <= bits) {
-                               // Single source word
-                               d0 >>= right;
-                       } else {
-                               // 2 source words
-                               d1 = FB_READL(src + 1);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-                               d0 = d0 >> right | d1 << left;
-                       }
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
-               } else {
-                       // Multiple destination words
-                       /** We must always remember the last value read, because in case
-                       SRC and DST overlap bitwise (e.g. when moving just one pixel in
-                       1bpp), we always collect one full long for DST and that might
-                       overlap with the current long from SRC. We store this value in
-                       'd0'. */
-                       d0 = FB_READL(src++);
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       // Leading bits
-                       if (shift > 0) {
-                               // Single source word
-                               d1 = d0;
-                               d0 <<= left;
-                               n -= bits - dst_idx;
-                       } else {
-                               // 2 source words
-                               d1 = FB_READL(src++);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-
-                               d0 = d0 >> right | d1 << left;
-                               n -= bits - dst_idx;
-                       }
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
-                       d0 = d1;
-                       dst++;
-
-                       // Main chunk
-                       m = n % bits;
-                       n /= bits;
-                       while ((n >= 4) && !bswapmask) {
-                               d1 = FB_READL(src++);
-                               FB_WRITEL(d0 >> right | d1 << left, dst++);
-                               d0 = d1;
-                               d1 = FB_READL(src++);
-                               FB_WRITEL(d0 >> right | d1 << left, dst++);
-                               d0 = d1;
-                               d1 = FB_READL(src++);
-                               FB_WRITEL(d0 >> right | d1 << left, dst++);
-                               d0 = d1;
-                               d1 = FB_READL(src++);
-                               FB_WRITEL(d0 >> right | d1 << left, dst++);
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = FB_READL(src++);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-                               d0 = d0 >> right | d1 << left;
-                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                               FB_WRITEL(d0, dst++);
-                               d0 = d1;
-                       }
-
-                       // Trailing bits
-                       if (m) {
-                               if (m <= bits - right) {
-                                       // Single source word
-                                       d0 >>= right;
-                               } else {
-                                       // 2 source words
-                                       d1 = FB_READL(src);
-                                       d1 = fb_rev_pixels_in_long(d1,
-                                                               bswapmask);
-                                       d0 = d0 >> right | d1 << left;
-                               }
-                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                               FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
-                       }
-               }
-       }
-}
-
-    /*
-     *  Generic bitwise copy algorithm, operating backward
-     */
-
-static void
-bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
-               const unsigned long __iomem *src, unsigned src_idx, int bits,
-               unsigned n, u32 bswapmask)
-{
-       unsigned long first, last;
-       int shift;
-
-#if 0
-       /*
-        * If you suspect bug in this function, compare it with this simple
-        * memmove implementation.
-        */
-       fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
-                  (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
-       return;
-#endif
-
-       dst += (dst_idx + n - 1) / bits;
-       src += (src_idx + n - 1) / bits;
-       dst_idx = (dst_idx + n - 1) % bits;
-       src_idx = (src_idx + n - 1) % bits;
-
-       shift = dst_idx-src_idx;
-
-       first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
-       last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
-
-       if (!shift) {
-               // Same alignment for source and dest
-
-               if ((unsigned long)dst_idx+1 >= n) {
-                       // Single word
-                       if (first)
-                               last &= first;
-                       FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
-               } else {
-                       // Multiple destination words
-
-                       // Leading bits
-                       if (first) {
-                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
-                               dst--;
-                               src--;
-                               n -= dst_idx+1;
-                       }
-
-                       // Main chunk
-                       n /= bits;
-                       while (n >= 8) {
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               FB_WRITEL(FB_READL(src--), dst--);
-                               n -= 8;
-                       }
-                       while (n--)
-                               FB_WRITEL(FB_READL(src--), dst--);
-
-                       // Trailing bits
-                       if (last != -1UL)
-                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
-               }
-       } else {
-               // Different alignment for source and dest
-               unsigned long d0, d1;
-               int m;
-
-               int const left = shift & (bits-1);
-               int const right = -shift & (bits-1);
-
-               if ((unsigned long)dst_idx+1 >= n) {
-                       // Single destination word
-                       if (first)
-                               last &= first;
-                       d0 = FB_READL(src);
-                       if (shift < 0) {
-                               // Single source word
-                               d0 >>= right;
-                       } else if (1+(unsigned long)src_idx >= n) {
-                               // Single source word
-                               d0 <<= left;
-                       } else {
-                               // 2 source words
-                               d1 = FB_READL(src - 1);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-                               d0 = d0 << left | d1 >> right;
-                       }
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
-               } else {
-                       // Multiple destination words
-                       /** We must always remember the last value read, because in case
-                       SRC and DST overlap bitwise (e.g. when moving just one pixel in
-                       1bpp), we always collect one full long for DST and that might
-                       overlap with the current long from SRC. We store this value in
-                       'd0'. */
-
-                       d0 = FB_READL(src--);
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       // Leading bits
-                       if (shift < 0) {
-                               // Single source word
-                               d1 = d0;
-                               d0 >>= right;
-                       } else {
-                               // 2 source words
-                               d1 = FB_READL(src--);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-                               d0 = d0 << left | d1 >> right;
-                       }
-                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
-                       d0 = d1;
-                       dst--;
-                       n -= dst_idx+1;
-
-                       // Main chunk
-                       m = n % bits;
-                       n /= bits;
-                       while ((n >= 4) && !bswapmask) {
-                               d1 = FB_READL(src--);
-                               FB_WRITEL(d0 << left | d1 >> right, dst--);
-                               d0 = d1;
-                               d1 = FB_READL(src--);
-                               FB_WRITEL(d0 << left | d1 >> right, dst--);
-                               d0 = d1;
-                               d1 = FB_READL(src--);
-                               FB_WRITEL(d0 << left | d1 >> right, dst--);
-                               d0 = d1;
-                               d1 = FB_READL(src--);
-                               FB_WRITEL(d0 << left | d1 >> right, dst--);
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = FB_READL(src--);
-                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
-                               d0 = d0 << left | d1 >> right;
-                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                               FB_WRITEL(d0, dst--);
-                               d0 = d1;
-                       }
-
-                       // Trailing bits
-                       if (m) {
-                               if (m <= bits - left) {
-                                       // Single source word
-                                       d0 <<= left;
-                               } else {
-                                       // 2 source words
-                                       d1 = FB_READL(src);
-                                       d1 = fb_rev_pixels_in_long(d1,
-                                                               bswapmask);
-                                       d0 = d0 << left | d1 >> right;
-                               }
-                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
-                               FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
-                       }
-               }
-       }
-}
-
-void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
-{
-       u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
-       u32 height = area->height, width = area->width;
-       unsigned long const bits_per_line = p->fix.line_length*8u;
-       unsigned long __iomem *base = NULL;
-       int bits = BITS_PER_LONG, bytes = bits >> 3;
-       unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
-       u32 bswapmask = fb_compute_bswapmask(p);
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       /* if the beginning of the target area might overlap with the end of
-       the source area, be have to copy the area reverse. */
-       if ((dy == sy && dx > sx) || (dy > sy)) {
-               dy += height;
-               sy += height;
-               rev_copy = 1;
-       }
-
-       // split the base of the framebuffer into a long-aligned address and the
-       // index of the first bit
-       base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
-       dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
-       // add offset of source and target area
-       dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
-       src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
-
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-
-       if (rev_copy) {
-               while (height--) {
-                       dst_idx -= bits_per_line;
-                       src_idx -= bits_per_line;
-                       bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
-                               base + (src_idx / bits), src_idx % bits, bits,
-                               width*p->var.bits_per_pixel, bswapmask);
-               }
-       } else {
-               while (height--) {
-                       bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
-                               base + (src_idx / bits), src_idx % bits, bits,
-                               width*p->var.bits_per_pixel, bswapmask);
-                       dst_idx += bits_per_line;
-                       src_idx += bits_per_line;
-               }
-       }
-}
-
-EXPORT_SYMBOL(cfb_copyarea);
-
-MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
-MODULE_DESCRIPTION("Generic software accelerated copyarea");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/fbdev/cfbfillrect.c b/drivers/video/fbdev/cfbfillrect.c
deleted file mode 100644 (file)
index ba9f58b..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- *  Generic fillrect for frame buffers with packed pixels of any depth.
- *
- *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
- *
- *  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.
- *
- * NOTES:
- *
- *  Also need to add code to deal with cards endians that are different than
- *  the native cpu endians. I also need to deal with MSB position in the word.
- *
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-#include "fb_draw.h"
-
-#if BITS_PER_LONG == 32
-#  define FB_WRITEL fb_writel
-#  define FB_READL  fb_readl
-#else
-#  define FB_WRITEL fb_writeq
-#  define FB_READL  fb_readq
-#endif
-
-    /*
-     *  Aligned pattern fill using 32/64-bit memory accesses
-     */
-
-static void
-bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
-               unsigned long pat, unsigned n, int bits, u32 bswapmask)
-{
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
-       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
-
-       if (dst_idx+n <= bits) {
-               // Single word
-               if (last)
-                       first &= last;
-               FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
-       } else {
-               // Multiple destination words
-
-               // Leading bits
-               if (first!= ~0UL) {
-                       FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
-                       dst++;
-                       n -= bits - dst_idx;
-               }
-
-               // Main chunk
-               n /= bits;
-               while (n >= 8) {
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       FB_WRITEL(pat, dst++);
-                       n -= 8;
-               }
-               while (n--)
-                       FB_WRITEL(pat, dst++);
-
-               // Trailing bits
-               if (last)
-                       FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
-       }
-}
-
-
-    /*
-     *  Unaligned generic pattern fill using 32/64-bit memory accesses
-     *  The pattern must have been expanded to a full 32/64-bit value
-     *  Left/right are the appropriate shifts to convert to the pattern to be
-     *  used for the next 32/64-bit word
-     */
-
-static void
-bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
-                 unsigned long pat, int left, int right, unsigned n, int bits)
-{
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               // Single word
-               if (last)
-                       first &= last;
-               FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
-       } else {
-               // Multiple destination words
-               // Leading bits
-               if (first) {
-                       FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       n -= bits - dst_idx;
-               }
-
-               // Main chunk
-               n /= bits;
-               while (n >= 4) {
-                       FB_WRITEL(pat, dst++);
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(pat, dst++);
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(pat, dst++);
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(pat, dst++);
-                       pat = pat << left | pat >> right;
-                       n -= 4;
-               }
-               while (n--) {
-                       FB_WRITEL(pat, dst++);
-                       pat = pat << left | pat >> right;
-               }
-
-               // Trailing bits
-               if (last)
-                       FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
-       }
-}
-
-    /*
-     *  Aligned pattern invert using 32/64-bit memory accesses
-     */
-static void
-bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
-                   int dst_idx, unsigned long pat, unsigned n, int bits,
-                   u32 bswapmask)
-{
-       unsigned long val = pat, dat;
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
-       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
-
-       if (dst_idx+n <= bits) {
-               // Single word
-               if (last)
-                       first &= last;
-               dat = FB_READL(dst);
-               FB_WRITEL(comp(dat ^ val, dat, first), dst);
-       } else {
-               // Multiple destination words
-               // Leading bits
-               if (first!=0UL) {
-                       dat = FB_READL(dst);
-                       FB_WRITEL(comp(dat ^ val, dat, first), dst);
-                       dst++;
-                       n -= bits - dst_idx;
-               }
-
-               // Main chunk
-               n /= bits;
-               while (n >= 8) {
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-                       n -= 8;
-               }
-               while (n--) {
-                       FB_WRITEL(FB_READL(dst) ^ val, dst);
-                       dst++;
-               }
-               // Trailing bits
-               if (last) {
-                       dat = FB_READL(dst);
-                       FB_WRITEL(comp(dat ^ val, dat, last), dst);
-               }
-       }
-}
-
-
-    /*
-     *  Unaligned generic pattern invert using 32/64-bit memory accesses
-     *  The pattern must have been expanded to a full 32/64-bit value
-     *  Left/right are the appropriate shifts to convert to the pattern to be
-     *  used for the next 32/64-bit word
-     */
-
-static void
-bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
-                     int dst_idx, unsigned long pat, int left, int right,
-                     unsigned n, int bits)
-{
-       unsigned long first, last, dat;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               // Single word
-               if (last)
-                       first &= last;
-               dat = FB_READL(dst);
-               FB_WRITEL(comp(dat ^ pat, dat, first), dst);
-       } else {
-               // Multiple destination words
-
-               // Leading bits
-               if (first != 0UL) {
-                       dat = FB_READL(dst);
-                       FB_WRITEL(comp(dat ^ pat, dat, first), dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       n -= bits - dst_idx;
-               }
-
-               // Main chunk
-               n /= bits;
-               while (n >= 4) {
-                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       n -= 4;
-               }
-               while (n--) {
-                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
-                       dst++;
-                       pat = pat << left | pat >> right;
-               }
-
-               // Trailing bits
-               if (last) {
-                       dat = FB_READL(dst);
-                       FB_WRITEL(comp(dat ^ pat, dat, last), dst);
-               }
-       }
-}
-
-void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
-{
-       unsigned long pat, pat2, fg;
-       unsigned long width = rect->width, height = rect->height;
-       int bits = BITS_PER_LONG, bytes = bits >> 3;
-       u32 bpp = p->var.bits_per_pixel;
-       unsigned long __iomem *dst;
-       int dst_idx, left;
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
-               fg = ((u32 *) (p->pseudo_palette))[rect->color];
-       else
-               fg = rect->color;
-
-       pat = pixel_to_pat(bpp, fg);
-
-       dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
-       dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
-       dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
-       /* FIXME For now we support 1-32 bpp only */
-       left = bits % bpp;
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-       if (!left) {
-               u32 bswapmask = fb_compute_bswapmask(p);
-               void (*fill_op32)(struct fb_info *p,
-                                 unsigned long __iomem *dst, int dst_idx,
-                                 unsigned long pat, unsigned n, int bits,
-                                 u32 bswapmask) = NULL;
-
-               switch (rect->rop) {
-               case ROP_XOR:
-                       fill_op32 = bitfill_aligned_rev;
-                       break;
-               case ROP_COPY:
-                       fill_op32 = bitfill_aligned;
-                       break;
-               default:
-                       printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
-                       fill_op32 = bitfill_aligned;
-                       break;
-               }
-               while (height--) {
-                       dst += dst_idx >> (ffs(bits) - 1);
-                       dst_idx &= (bits - 1);
-                       fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
-                                 bswapmask);
-                       dst_idx += p->fix.line_length*8;
-               }
-       } else {
-               int right, r;
-               void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
-                               int dst_idx, unsigned long pat, int left,
-                               int right, unsigned n, int bits) = NULL;
-#ifdef __LITTLE_ENDIAN
-               right = left;
-               left = bpp - right;
-#else
-               right = bpp - left;
-#endif
-               switch (rect->rop) {
-               case ROP_XOR:
-                       fill_op = bitfill_unaligned_rev;
-                       break;
-               case ROP_COPY:
-                       fill_op = bitfill_unaligned;
-                       break;
-               default:
-                       printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
-                       fill_op = bitfill_unaligned;
-                       break;
-               }
-               while (height--) {
-                       dst += dst_idx / bits;
-                       dst_idx &= (bits - 1);
-                       r = dst_idx % bpp;
-                       /* rotate pattern to the correct start position */
-                       pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
-                       fill_op(p, dst, dst_idx, pat2, left, right,
-                               width*bpp, bits);
-                       dst_idx += p->fix.line_length*8;
-               }
-       }
-}
-
-EXPORT_SYMBOL(cfb_fillrect);
-
-MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
-MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/cfbimgblt.c b/drivers/video/fbdev/cfbimgblt.c
deleted file mode 100644 (file)
index a2bb276..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- *  Generic BitBLT function for frame buffer with packed pixels of any depth.
- *
- *      Copyright (C)  June 1999 James Simmons
- *
- *  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.
- *
- * NOTES:
- *
- *    This function copys a image from system memory to video memory. The
- *  image can be a bitmap where each 0 represents the background color and
- *  each 1 represents the foreground color. Great for font handling. It can
- *  also be a color image. This is determined by image_depth. The color image
- *  must be laid out exactly in the same format as the framebuffer. Yes I know
- *  their are cards with hardware that coverts images of various depths to the
- *  framebuffer depth. But not every card has this. All images must be rounded
- *  up to the nearest byte. For example a bitmap 12 bits wide must be two 
- *  bytes width. 
- *
- *  Tony: 
- *  Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API.  This speeds 
- *  up the code significantly.
- *  
- *  Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
- *  still processed a bit at a time.   
- *
- *  Also need to add code to deal with cards endians that are different than
- *  the native cpu endians. I also need to deal with MSB position in the word.
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-#include "fb_draw.h"
-
-#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-static const u32 cfb_tab8_be[] = {
-    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
-    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
-    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
-    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
-};
-
-static const u32 cfb_tab8_le[] = {
-    0x00000000,0xff000000,0x00ff0000,0xffff0000,
-    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
-    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
-    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
-};
-
-static const u32 cfb_tab16_be[] = {
-    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
-};
-
-static const u32 cfb_tab16_le[] = {
-    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
-};
-
-static const u32 cfb_tab32[] = {
-       0x00000000, 0xffffffff
-};
-
-#define FB_WRITEL fb_writel
-#define FB_READL  fb_readl
-
-static inline void color_imageblit(const struct fb_image *image, 
-                                  struct fb_info *p, u8 __iomem *dst1, 
-                                  u32 start_index,
-                                  u32 pitch_index)
-{
-       /* Draw the penguin */
-       u32 __iomem *dst, *dst2;
-       u32 color = 0, val, shift;
-       int i, n, bpp = p->var.bits_per_pixel;
-       u32 null_bits = 32 - bpp;
-       u32 *palette = (u32 *) p->pseudo_palette;
-       const u8 *src = image->data;
-       u32 bswapmask = fb_compute_bswapmask(p);
-
-       dst2 = (u32 __iomem *) dst1;
-       for (i = image->height; i--; ) {
-               n = image->width;
-               dst = (u32 __iomem *) dst1;
-               shift = 0;
-               val = 0;
-               
-               if (start_index) {
-                       u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
-                                               start_index, bswapmask);
-                       val = FB_READL(dst) & start_mask;
-                       shift = start_index;
-               }
-               while (n--) {
-                       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-                           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
-                               color = palette[*src];
-                       else
-                               color = *src;
-                       color <<= FB_LEFT_POS(p, bpp);
-                       val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
-                       if (shift >= null_bits) {
-                               FB_WRITEL(val, dst++);
-       
-                               val = (shift == null_bits) ? 0 : 
-                                       FB_SHIFT_LOW(p, color, 32 - shift);
-                       }
-                       shift += bpp;
-                       shift &= (32 - 1);
-                       src++;
-               }
-               if (shift) {
-                       u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
-                                               bswapmask);
-
-                       FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
-               }
-               dst1 += p->fix.line_length;
-               if (pitch_index) {
-                       dst2 += p->fix.line_length;
-                       dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
-
-                       start_index += pitch_index;
-                       start_index &= 32 - 1;
-               }
-       }
-}
-
-static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, 
-                                 u8 __iomem *dst1, u32 fgcolor,
-                                 u32 bgcolor, 
-                                 u32 start_index,
-                                 u32 pitch_index)
-{
-       u32 shift, color = 0, bpp = p->var.bits_per_pixel;
-       u32 __iomem *dst, *dst2;
-       u32 val, pitch = p->fix.line_length;
-       u32 null_bits = 32 - bpp;
-       u32 spitch = (image->width+7)/8;
-       const u8 *src = image->data, *s;
-       u32 i, j, l;
-       u32 bswapmask = fb_compute_bswapmask(p);
-
-       dst2 = (u32 __iomem *) dst1;
-       fgcolor <<= FB_LEFT_POS(p, bpp);
-       bgcolor <<= FB_LEFT_POS(p, bpp);
-
-       for (i = image->height; i--; ) {
-               shift = val = 0;
-               l = 8;
-               j = image->width;
-               dst = (u32 __iomem *) dst1;
-               s = src;
-
-               /* write leading bits */
-               if (start_index) {
-                       u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
-                                               start_index, bswapmask);
-                       val = FB_READL(dst) & start_mask;
-                       shift = start_index;
-               }
-
-               while (j--) {
-                       l--;
-                       color = (*s & (1 << l)) ? fgcolor : bgcolor;
-                       val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
-                       
-                       /* Did the bitshift spill bits to the next long? */
-                       if (shift >= null_bits) {
-                               FB_WRITEL(val, dst++);
-                               val = (shift == null_bits) ? 0 :
-                                       FB_SHIFT_LOW(p, color, 32 - shift);
-                       }
-                       shift += bpp;
-                       shift &= (32 - 1);
-                       if (!l) { l = 8; s++; }
-               }
-
-               /* write trailing bits */
-               if (shift) {
-                       u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
-                                               bswapmask);
-
-                       FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
-               }
-               
-               dst1 += pitch;
-               src += spitch;  
-               if (pitch_index) {
-                       dst2 += pitch;
-                       dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
-                       start_index += pitch_index;
-                       start_index &= 32 - 1;
-               }
-               
-       }
-}
-
-/*
- * fast_imageblit - optimized monochrome color expansion
- *
- * Only if:  bits_per_pixel == 8, 16, or 32
- *           image->width is divisible by pixel/dword (ppw);
- *           fix->line_legth is divisible by 4;
- *           beginning and end of a scanline is dword aligned
- */
-static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, 
-                                 u8 __iomem *dst1, u32 fgcolor, 
-                                 u32 bgcolor) 
-{
-       u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
-       u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
-       u32 bit_mask, end_mask, eorx, shift;
-       const char *s = image->data, *src;
-       u32 __iomem *dst;
-       const u32 *tab = NULL;
-       int i, j, k;
-
-       switch (bpp) {
-       case 8:
-               tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
-               break;
-       case 16:
-               tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
-               break;
-       case 32:
-       default:
-               tab = cfb_tab32;
-               break;
-       }
-
-       for (i = ppw-1; i--; ) {
-               fgx <<= bpp;
-               bgx <<= bpp;
-               fgx |= fgcolor;
-               bgx |= bgcolor;
-       }
-       
-       bit_mask = (1 << ppw) - 1;
-       eorx = fgx ^ bgx;
-       k = image->width/ppw;
-
-       for (i = image->height; i--; ) {
-               dst = (u32 __iomem *) dst1, shift = 8; src = s;
-               
-               for (j = k; j--; ) {
-                       shift -= ppw;
-                       end_mask = tab[(*src >> shift) & bit_mask];
-                       FB_WRITEL((end_mask & eorx)^bgx, dst++);
-                       if (!shift) { shift = 8; src++; }               
-               }
-               dst1 += p->fix.line_length;
-               s += spitch;
-       }
-}      
-       
-void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
-{
-       u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
-       u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
-       u32 width = image->width;
-       u32 dx = image->dx, dy = image->dy;
-       u8 __iomem *dst1;
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
-       start_index = bitstart & (32 - 1);
-       pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
-
-       bitstart /= 8;
-       bitstart &= ~(bpl - 1);
-       dst1 = p->screen_base + bitstart;
-
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-
-       if (image->depth == 1) {
-               if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-                   p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-                       fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
-                       bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
-               } else {
-                       fgcolor = image->fg_color;
-                       bgcolor = image->bg_color;
-               }       
-               
-               if (32 % bpp == 0 && !start_index && !pitch_index && 
-                   ((width & (32/bpp-1)) == 0) &&
-                   bpp >= 8 && bpp <= 32)                      
-                       fast_imageblit(image, p, dst1, fgcolor, bgcolor);
-               else 
-                       slow_imageblit(image, p, dst1, fgcolor, bgcolor,
-                                       start_index, pitch_index);
-       } else
-               color_imageblit(image, p, dst1, start_index, pitch_index);
-}
-
-EXPORT_SYMBOL(cfb_imageblit);
-
-MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
-MODULE_DESCRIPTION("Generic software accelerated imaging drawing");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
new file mode 100644 (file)
index 0000000..fa30653
--- /dev/null
@@ -0,0 +1,16 @@
+obj-y                             += fb_notify.o
+obj-$(CONFIG_FB)                  += fb.o
+fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
+                                     modedb.o fbcvt.o
+fb-objs                           := $(fb-y)
+
+obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
+obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
+obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SYS_FILLRECT)  += sysfillrect.o
+obj-$(CONFIG_FB_SYS_COPYAREA)  += syscopyarea.o
+obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
+obj-$(CONFIG_FB_SYS_FOPS)      += fb_sys_fops.o
+obj-$(CONFIG_FB_SVGALIB)       += svgalib.o
+obj-$(CONFIG_FB_DDC)           += fb_ddc.o
+obj-$(CONFIG_FB_DEFERRED_IO)   += fb_defio.o
diff --git a/drivers/video/fbdev/core/cfbcopyarea.c b/drivers/video/fbdev/core/cfbcopyarea.c
new file mode 100644 (file)
index 0000000..bcb5723
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  Generic function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *  This is for cfb packed pixels. Iplan and such are incorporated in the
+ *  drivers that need them.
+ *
+ *  FIXME
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ *  The two functions or copying forward and backward could be split up like
+ *  the ones for filling, i.e. in aligned and unaligned versions. This would
+ *  help moving some redundant computations and branches out of the loop, too.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "fb_draw.h"
+
+#if BITS_PER_LONG == 32
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
+#else
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
+#endif
+
+    /*
+     *  Generic bitwise copy algorithm
+     */
+
+static void
+bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
+               const unsigned long __iomem *src, unsigned src_idx, int bits,
+               unsigned n, u32 bswapmask)
+{
+       unsigned long first, last;
+       int const shift = dst_idx-src_idx;
+
+#if 0
+       /*
+        * If you suspect bug in this function, compare it with this simple
+        * memmove implementation.
+        */
+       fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
+                  (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
+       return;
+#endif
+
+       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
+
+       if (!shift) {
+               // Same alignment for source and dest
+
+               if (dst_idx+n <= bits) {
+                       // Single word
+                       if (last)
+                               first &= last;
+                       FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+               } else {
+                       // Multiple destination words
+
+                       // Leading bits
+                       if (first != ~0UL) {
+                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+                               dst++;
+                               src++;
+                               n -= bits - dst_idx;
+                       }
+
+                       // Main chunk
+                       n /= bits;
+                       while (n >= 8) {
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               FB_WRITEL(FB_READL(src++), dst++);
+                               n -= 8;
+                       }
+                       while (n--)
+                               FB_WRITEL(FB_READL(src++), dst++);
+
+                       // Trailing bits
+                       if (last)
+                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
+               }
+       } else {
+               /* Different alignment for source and dest */
+               unsigned long d0, d1;
+               int m;
+
+               int const left = shift & (bits - 1);
+               int const right = -shift & (bits - 1);
+
+               if (dst_idx+n <= bits) {
+                       // Single destination word
+                       if (last)
+                               first &= last;
+                       d0 = FB_READL(src);
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       if (shift > 0) {
+                               // Single source word
+                               d0 <<= left;
+                       } else if (src_idx+n <= bits) {
+                               // Single source word
+                               d0 >>= right;
+                       } else {
+                               // 2 source words
+                               d1 = FB_READL(src + 1);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+                               d0 = d0 >> right | d1 << left;
+                       }
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+               } else {
+                       // Multiple destination words
+                       /** We must always remember the last value read, because in case
+                       SRC and DST overlap bitwise (e.g. when moving just one pixel in
+                       1bpp), we always collect one full long for DST and that might
+                       overlap with the current long from SRC. We store this value in
+                       'd0'. */
+                       d0 = FB_READL(src++);
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       // Leading bits
+                       if (shift > 0) {
+                               // Single source word
+                               d1 = d0;
+                               d0 <<= left;
+                               n -= bits - dst_idx;
+                       } else {
+                               // 2 source words
+                               d1 = FB_READL(src++);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+
+                               d0 = d0 >> right | d1 << left;
+                               n -= bits - dst_idx;
+                       }
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+                       d0 = d1;
+                       dst++;
+
+                       // Main chunk
+                       m = n % bits;
+                       n /= bits;
+                       while ((n >= 4) && !bswapmask) {
+                               d1 = FB_READL(src++);
+                               FB_WRITEL(d0 >> right | d1 << left, dst++);
+                               d0 = d1;
+                               d1 = FB_READL(src++);
+                               FB_WRITEL(d0 >> right | d1 << left, dst++);
+                               d0 = d1;
+                               d1 = FB_READL(src++);
+                               FB_WRITEL(d0 >> right | d1 << left, dst++);
+                               d0 = d1;
+                               d1 = FB_READL(src++);
+                               FB_WRITEL(d0 >> right | d1 << left, dst++);
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = FB_READL(src++);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+                               d0 = d0 >> right | d1 << left;
+                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                               FB_WRITEL(d0, dst++);
+                               d0 = d1;
+                       }
+
+                       // Trailing bits
+                       if (m) {
+                               if (m <= bits - right) {
+                                       // Single source word
+                                       d0 >>= right;
+                               } else {
+                                       // 2 source words
+                                       d1 = FB_READL(src);
+                                       d1 = fb_rev_pixels_in_long(d1,
+                                                               bswapmask);
+                                       d0 = d0 >> right | d1 << left;
+                               }
+                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                               FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
+                       }
+               }
+       }
+}
+
+    /*
+     *  Generic bitwise copy algorithm, operating backward
+     */
+
+static void
+bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
+               const unsigned long __iomem *src, unsigned src_idx, int bits,
+               unsigned n, u32 bswapmask)
+{
+       unsigned long first, last;
+       int shift;
+
+#if 0
+       /*
+        * If you suspect bug in this function, compare it with this simple
+        * memmove implementation.
+        */
+       fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
+                  (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
+       return;
+#endif
+
+       dst += (dst_idx + n - 1) / bits;
+       src += (src_idx + n - 1) / bits;
+       dst_idx = (dst_idx + n - 1) % bits;
+       src_idx = (src_idx + n - 1) % bits;
+
+       shift = dst_idx-src_idx;
+
+       first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
+       last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
+
+       if (!shift) {
+               // Same alignment for source and dest
+
+               if ((unsigned long)dst_idx+1 >= n) {
+                       // Single word
+                       if (first)
+                               last &= first;
+                       FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
+               } else {
+                       // Multiple destination words
+
+                       // Leading bits
+                       if (first) {
+                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+                               dst--;
+                               src--;
+                               n -= dst_idx+1;
+                       }
+
+                       // Main chunk
+                       n /= bits;
+                       while (n >= 8) {
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               FB_WRITEL(FB_READL(src--), dst--);
+                               n -= 8;
+                       }
+                       while (n--)
+                               FB_WRITEL(FB_READL(src--), dst--);
+
+                       // Trailing bits
+                       if (last != -1UL)
+                               FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
+               }
+       } else {
+               // Different alignment for source and dest
+               unsigned long d0, d1;
+               int m;
+
+               int const left = shift & (bits-1);
+               int const right = -shift & (bits-1);
+
+               if ((unsigned long)dst_idx+1 >= n) {
+                       // Single destination word
+                       if (first)
+                               last &= first;
+                       d0 = FB_READL(src);
+                       if (shift < 0) {
+                               // Single source word
+                               d0 >>= right;
+                       } else if (1+(unsigned long)src_idx >= n) {
+                               // Single source word
+                               d0 <<= left;
+                       } else {
+                               // 2 source words
+                               d1 = FB_READL(src - 1);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+                               d0 = d0 << left | d1 >> right;
+                       }
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
+               } else {
+                       // Multiple destination words
+                       /** We must always remember the last value read, because in case
+                       SRC and DST overlap bitwise (e.g. when moving just one pixel in
+                       1bpp), we always collect one full long for DST and that might
+                       overlap with the current long from SRC. We store this value in
+                       'd0'. */
+
+                       d0 = FB_READL(src--);
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       // Leading bits
+                       if (shift < 0) {
+                               // Single source word
+                               d1 = d0;
+                               d0 >>= right;
+                       } else {
+                               // 2 source words
+                               d1 = FB_READL(src--);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+                               d0 = d0 << left | d1 >> right;
+                       }
+                       d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                       FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+                       d0 = d1;
+                       dst--;
+                       n -= dst_idx+1;
+
+                       // Main chunk
+                       m = n % bits;
+                       n /= bits;
+                       while ((n >= 4) && !bswapmask) {
+                               d1 = FB_READL(src--);
+                               FB_WRITEL(d0 << left | d1 >> right, dst--);
+                               d0 = d1;
+                               d1 = FB_READL(src--);
+                               FB_WRITEL(d0 << left | d1 >> right, dst--);
+                               d0 = d1;
+                               d1 = FB_READL(src--);
+                               FB_WRITEL(d0 << left | d1 >> right, dst--);
+                               d0 = d1;
+                               d1 = FB_READL(src--);
+                               FB_WRITEL(d0 << left | d1 >> right, dst--);
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = FB_READL(src--);
+                               d1 = fb_rev_pixels_in_long(d1, bswapmask);
+                               d0 = d0 << left | d1 >> right;
+                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                               FB_WRITEL(d0, dst--);
+                               d0 = d1;
+                       }
+
+                       // Trailing bits
+                       if (m) {
+                               if (m <= bits - left) {
+                                       // Single source word
+                                       d0 <<= left;
+                               } else {
+                                       // 2 source words
+                                       d1 = FB_READL(src);
+                                       d1 = fb_rev_pixels_in_long(d1,
+                                                               bswapmask);
+                                       d0 = d0 << left | d1 >> right;
+                               }
+                               d0 = fb_rev_pixels_in_long(d0, bswapmask);
+                               FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
+                       }
+               }
+       }
+}
+
+void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+       u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+       u32 height = area->height, width = area->width;
+       unsigned long const bits_per_line = p->fix.line_length*8u;
+       unsigned long __iomem *base = NULL;
+       int bits = BITS_PER_LONG, bytes = bits >> 3;
+       unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
+       u32 bswapmask = fb_compute_bswapmask(p);
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       /* if the beginning of the target area might overlap with the end of
+       the source area, be have to copy the area reverse. */
+       if ((dy == sy && dx > sx) || (dy > sy)) {
+               dy += height;
+               sy += height;
+               rev_copy = 1;
+       }
+
+       // split the base of the framebuffer into a long-aligned address and the
+       // index of the first bit
+       base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+       dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+       // add offset of source and target area
+       dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+       src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+
+       if (rev_copy) {
+               while (height--) {
+                       dst_idx -= bits_per_line;
+                       src_idx -= bits_per_line;
+                       bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
+                               base + (src_idx / bits), src_idx % bits, bits,
+                               width*p->var.bits_per_pixel, bswapmask);
+               }
+       } else {
+               while (height--) {
+                       bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
+                               base + (src_idx / bits), src_idx % bits, bits,
+                               width*p->var.bits_per_pixel, bswapmask);
+                       dst_idx += bits_per_line;
+                       src_idx += bits_per_line;
+               }
+       }
+}
+
+EXPORT_SYMBOL(cfb_copyarea);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated copyarea");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/fbdev/core/cfbfillrect.c b/drivers/video/fbdev/core/cfbfillrect.c
new file mode 100644 (file)
index 0000000..ba9f58b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ *  Generic fillrect for frame buffers with packed pixels of any depth.
+ *
+ *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ *
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include "fb_draw.h"
+
+#if BITS_PER_LONG == 32
+#  define FB_WRITEL fb_writel
+#  define FB_READL  fb_readl
+#else
+#  define FB_WRITEL fb_writeq
+#  define FB_READL  fb_readq
+#endif
+
+    /*
+     *  Aligned pattern fill using 32/64-bit memory accesses
+     */
+
+static void
+bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+               unsigned long pat, unsigned n, int bits, u32 bswapmask)
+{
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
+
+       if (dst_idx+n <= bits) {
+               // Single word
+               if (last)
+                       first &= last;
+               FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+       } else {
+               // Multiple destination words
+
+               // Leading bits
+               if (first!= ~0UL) {
+                       FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+                       dst++;
+                       n -= bits - dst_idx;
+               }
+
+               // Main chunk
+               n /= bits;
+               while (n >= 8) {
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       FB_WRITEL(pat, dst++);
+                       n -= 8;
+               }
+               while (n--)
+                       FB_WRITEL(pat, dst++);
+
+               // Trailing bits
+               if (last)
+                       FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
+       }
+}
+
+
+    /*
+     *  Unaligned generic pattern fill using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+                 unsigned long pat, int left, int right, unsigned n, int bits)
+{
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               // Single word
+               if (last)
+                       first &= last;
+               FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+       } else {
+               // Multiple destination words
+               // Leading bits
+               if (first) {
+                       FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       n -= bits - dst_idx;
+               }
+
+               // Main chunk
+               n /= bits;
+               while (n >= 4) {
+                       FB_WRITEL(pat, dst++);
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(pat, dst++);
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(pat, dst++);
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(pat, dst++);
+                       pat = pat << left | pat >> right;
+                       n -= 4;
+               }
+               while (n--) {
+                       FB_WRITEL(pat, dst++);
+                       pat = pat << left | pat >> right;
+               }
+
+               // Trailing bits
+               if (last)
+                       FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
+       }
+}
+
+    /*
+     *  Aligned pattern invert using 32/64-bit memory accesses
+     */
+static void
+bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
+                   int dst_idx, unsigned long pat, unsigned n, int bits,
+                   u32 bswapmask)
+{
+       unsigned long val = pat, dat;
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+       last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
+
+       if (dst_idx+n <= bits) {
+               // Single word
+               if (last)
+                       first &= last;
+               dat = FB_READL(dst);
+               FB_WRITEL(comp(dat ^ val, dat, first), dst);
+       } else {
+               // Multiple destination words
+               // Leading bits
+               if (first!=0UL) {
+                       dat = FB_READL(dst);
+                       FB_WRITEL(comp(dat ^ val, dat, first), dst);
+                       dst++;
+                       n -= bits - dst_idx;
+               }
+
+               // Main chunk
+               n /= bits;
+               while (n >= 8) {
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+                       n -= 8;
+               }
+               while (n--) {
+                       FB_WRITEL(FB_READL(dst) ^ val, dst);
+                       dst++;
+               }
+               // Trailing bits
+               if (last) {
+                       dat = FB_READL(dst);
+                       FB_WRITEL(comp(dat ^ val, dat, last), dst);
+               }
+       }
+}
+
+
+    /*
+     *  Unaligned generic pattern invert using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
+                     int dst_idx, unsigned long pat, int left, int right,
+                     unsigned n, int bits)
+{
+       unsigned long first, last, dat;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               // Single word
+               if (last)
+                       first &= last;
+               dat = FB_READL(dst);
+               FB_WRITEL(comp(dat ^ pat, dat, first), dst);
+       } else {
+               // Multiple destination words
+
+               // Leading bits
+               if (first != 0UL) {
+                       dat = FB_READL(dst);
+                       FB_WRITEL(comp(dat ^ pat, dat, first), dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       n -= bits - dst_idx;
+               }
+
+               // Main chunk
+               n /= bits;
+               while (n >= 4) {
+                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       n -= 4;
+               }
+               while (n--) {
+                       FB_WRITEL(FB_READL(dst) ^ pat, dst);
+                       dst++;
+                       pat = pat << left | pat >> right;
+               }
+
+               // Trailing bits
+               if (last) {
+                       dat = FB_READL(dst);
+                       FB_WRITEL(comp(dat ^ pat, dat, last), dst);
+               }
+       }
+}
+
+void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+       unsigned long pat, pat2, fg;
+       unsigned long width = rect->width, height = rect->height;
+       int bits = BITS_PER_LONG, bytes = bits >> 3;
+       u32 bpp = p->var.bits_per_pixel;
+       unsigned long __iomem *dst;
+       int dst_idx, left;
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+               fg = ((u32 *) (p->pseudo_palette))[rect->color];
+       else
+               fg = rect->color;
+
+       pat = pixel_to_pat(bpp, fg);
+
+       dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+       dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
+       dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
+       /* FIXME For now we support 1-32 bpp only */
+       left = bits % bpp;
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+       if (!left) {
+               u32 bswapmask = fb_compute_bswapmask(p);
+               void (*fill_op32)(struct fb_info *p,
+                                 unsigned long __iomem *dst, int dst_idx,
+                                 unsigned long pat, unsigned n, int bits,
+                                 u32 bswapmask) = NULL;
+
+               switch (rect->rop) {
+               case ROP_XOR:
+                       fill_op32 = bitfill_aligned_rev;
+                       break;
+               case ROP_COPY:
+                       fill_op32 = bitfill_aligned;
+                       break;
+               default:
+                       printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+                       fill_op32 = bitfill_aligned;
+                       break;
+               }
+               while (height--) {
+                       dst += dst_idx >> (ffs(bits) - 1);
+                       dst_idx &= (bits - 1);
+                       fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
+                                 bswapmask);
+                       dst_idx += p->fix.line_length*8;
+               }
+       } else {
+               int right, r;
+               void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
+                               int dst_idx, unsigned long pat, int left,
+                               int right, unsigned n, int bits) = NULL;
+#ifdef __LITTLE_ENDIAN
+               right = left;
+               left = bpp - right;
+#else
+               right = bpp - left;
+#endif
+               switch (rect->rop) {
+               case ROP_XOR:
+                       fill_op = bitfill_unaligned_rev;
+                       break;
+               case ROP_COPY:
+                       fill_op = bitfill_unaligned;
+                       break;
+               default:
+                       printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
+                       fill_op = bitfill_unaligned;
+                       break;
+               }
+               while (height--) {
+                       dst += dst_idx / bits;
+                       dst_idx &= (bits - 1);
+                       r = dst_idx % bpp;
+                       /* rotate pattern to the correct start position */
+                       pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
+                       fill_op(p, dst, dst_idx, pat2, left, right,
+                               width*bpp, bits);
+                       dst_idx += p->fix.line_length*8;
+               }
+       }
+}
+
+EXPORT_SYMBOL(cfb_fillrect);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c
new file mode 100644 (file)
index 0000000..a2bb276
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ *  Generic BitBLT function for frame buffer with packed pixels of any depth.
+ *
+ *      Copyright (C)  June 1999 James Simmons
+ *
+ *  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.
+ *
+ * NOTES:
+ *
+ *    This function copys a image from system memory to video memory. The
+ *  image can be a bitmap where each 0 represents the background color and
+ *  each 1 represents the foreground color. Great for font handling. It can
+ *  also be a color image. This is determined by image_depth. The color image
+ *  must be laid out exactly in the same format as the framebuffer. Yes I know
+ *  their are cards with hardware that coverts images of various depths to the
+ *  framebuffer depth. But not every card has this. All images must be rounded
+ *  up to the nearest byte. For example a bitmap 12 bits wide must be two 
+ *  bytes width. 
+ *
+ *  Tony: 
+ *  Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API.  This speeds 
+ *  up the code significantly.
+ *  
+ *  Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
+ *  still processed a bit at a time.   
+ *
+ *  Also need to add code to deal with cards endians that are different than
+ *  the native cpu endians. I also need to deal with MSB position in the word.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include "fb_draw.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+static const u32 cfb_tab8_be[] = {
+    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+};
+
+static const u32 cfb_tab8_le[] = {
+    0x00000000,0xff000000,0x00ff0000,0xffff0000,
+    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+};
+
+static const u32 cfb_tab16_be[] = {
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+};
+
+static const u32 cfb_tab16_le[] = {
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+};
+
+static const u32 cfb_tab32[] = {
+       0x00000000, 0xffffffff
+};
+
+#define FB_WRITEL fb_writel
+#define FB_READL  fb_readl
+
+static inline void color_imageblit(const struct fb_image *image, 
+                                  struct fb_info *p, u8 __iomem *dst1, 
+                                  u32 start_index,
+                                  u32 pitch_index)
+{
+       /* Draw the penguin */
+       u32 __iomem *dst, *dst2;
+       u32 color = 0, val, shift;
+       int i, n, bpp = p->var.bits_per_pixel;
+       u32 null_bits = 32 - bpp;
+       u32 *palette = (u32 *) p->pseudo_palette;
+       const u8 *src = image->data;
+       u32 bswapmask = fb_compute_bswapmask(p);
+
+       dst2 = (u32 __iomem *) dst1;
+       for (i = image->height; i--; ) {
+               n = image->width;
+               dst = (u32 __iomem *) dst1;
+               shift = 0;
+               val = 0;
+               
+               if (start_index) {
+                       u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
+                                               start_index, bswapmask);
+                       val = FB_READL(dst) & start_mask;
+                       shift = start_index;
+               }
+               while (n--) {
+                       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+                           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+                               color = palette[*src];
+                       else
+                               color = *src;
+                       color <<= FB_LEFT_POS(p, bpp);
+                       val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
+                       if (shift >= null_bits) {
+                               FB_WRITEL(val, dst++);
+       
+                               val = (shift == null_bits) ? 0 : 
+                                       FB_SHIFT_LOW(p, color, 32 - shift);
+                       }
+                       shift += bpp;
+                       shift &= (32 - 1);
+                       src++;
+               }
+               if (shift) {
+                       u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
+                                               bswapmask);
+
+                       FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+               }
+               dst1 += p->fix.line_length;
+               if (pitch_index) {
+                       dst2 += p->fix.line_length;
+                       dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
+
+                       start_index += pitch_index;
+                       start_index &= 32 - 1;
+               }
+       }
+}
+
+static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, 
+                                 u8 __iomem *dst1, u32 fgcolor,
+                                 u32 bgcolor, 
+                                 u32 start_index,
+                                 u32 pitch_index)
+{
+       u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+       u32 __iomem *dst, *dst2;
+       u32 val, pitch = p->fix.line_length;
+       u32 null_bits = 32 - bpp;
+       u32 spitch = (image->width+7)/8;
+       const u8 *src = image->data, *s;
+       u32 i, j, l;
+       u32 bswapmask = fb_compute_bswapmask(p);
+
+       dst2 = (u32 __iomem *) dst1;
+       fgcolor <<= FB_LEFT_POS(p, bpp);
+       bgcolor <<= FB_LEFT_POS(p, bpp);
+
+       for (i = image->height; i--; ) {
+               shift = val = 0;
+               l = 8;
+               j = image->width;
+               dst = (u32 __iomem *) dst1;
+               s = src;
+
+               /* write leading bits */
+               if (start_index) {
+                       u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
+                                               start_index, bswapmask);
+                       val = FB_READL(dst) & start_mask;
+                       shift = start_index;
+               }
+
+               while (j--) {
+                       l--;
+                       color = (*s & (1 << l)) ? fgcolor : bgcolor;
+                       val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
+                       
+                       /* Did the bitshift spill bits to the next long? */
+                       if (shift >= null_bits) {
+                               FB_WRITEL(val, dst++);
+                               val = (shift == null_bits) ? 0 :
+                                       FB_SHIFT_LOW(p, color, 32 - shift);
+                       }
+                       shift += bpp;
+                       shift &= (32 - 1);
+                       if (!l) { l = 8; s++; }
+               }
+
+               /* write trailing bits */
+               if (shift) {
+                       u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
+                                               bswapmask);
+
+                       FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+               }
+               
+               dst1 += pitch;
+               src += spitch;  
+               if (pitch_index) {
+                       dst2 += pitch;
+                       dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
+                       start_index += pitch_index;
+                       start_index &= 32 - 1;
+               }
+               
+       }
+}
+
+/*
+ * fast_imageblit - optimized monochrome color expansion
+ *
+ * Only if:  bits_per_pixel == 8, 16, or 32
+ *           image->width is divisible by pixel/dword (ppw);
+ *           fix->line_legth is divisible by 4;
+ *           beginning and end of a scanline is dword aligned
+ */
+static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, 
+                                 u8 __iomem *dst1, u32 fgcolor, 
+                                 u32 bgcolor) 
+{
+       u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+       u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+       u32 bit_mask, end_mask, eorx, shift;
+       const char *s = image->data, *src;
+       u32 __iomem *dst;
+       const u32 *tab = NULL;
+       int i, j, k;
+
+       switch (bpp) {
+       case 8:
+               tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
+               break;
+       case 16:
+               tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
+               break;
+       case 32:
+       default:
+               tab = cfb_tab32;
+               break;
+       }
+
+       for (i = ppw-1; i--; ) {
+               fgx <<= bpp;
+               bgx <<= bpp;
+               fgx |= fgcolor;
+               bgx |= bgcolor;
+       }
+       
+       bit_mask = (1 << ppw) - 1;
+       eorx = fgx ^ bgx;
+       k = image->width/ppw;
+
+       for (i = image->height; i--; ) {
+               dst = (u32 __iomem *) dst1, shift = 8; src = s;
+               
+               for (j = k; j--; ) {
+                       shift -= ppw;
+                       end_mask = tab[(*src >> shift) & bit_mask];
+                       FB_WRITEL((end_mask & eorx)^bgx, dst++);
+                       if (!shift) { shift = 8; src++; }               
+               }
+               dst1 += p->fix.line_length;
+               s += spitch;
+       }
+}      
+       
+void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+       u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+       u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
+       u32 width = image->width;
+       u32 dx = image->dx, dy = image->dy;
+       u8 __iomem *dst1;
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
+       start_index = bitstart & (32 - 1);
+       pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
+
+       bitstart /= 8;
+       bitstart &= ~(bpl - 1);
+       dst1 = p->screen_base + bitstart;
+
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+
+       if (image->depth == 1) {
+               if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+                   p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+                       fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
+                       bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
+               } else {
+                       fgcolor = image->fg_color;
+                       bgcolor = image->bg_color;
+               }       
+               
+               if (32 % bpp == 0 && !start_index && !pitch_index && 
+                   ((width & (32/bpp-1)) == 0) &&
+                   bpp >= 8 && bpp <= 32)                      
+                       fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+               else 
+                       slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+                                       start_index, pitch_index);
+       } else
+               color_imageblit(image, p, dst1, start_index, pitch_index);
+}
+
+EXPORT_SYMBOL(cfb_imageblit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
+MODULE_DESCRIPTION("Generic software accelerated imaging drawing");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/fbdev/core/fb_ddc.c b/drivers/video/fbdev/core/fb_ddc.c
new file mode 100644 (file)
index 0000000..94322cc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * drivers/video/fb_ddc.c - DDC/EDID read support.
+ *
+ *  Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/slab.h>
+
+#include "../edid.h"
+
+#define DDC_ADDR       0x50
+
+static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+       unsigned char start = 0x0;
+       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = DDC_ADDR,
+                       .flags  = 0,
+                       .len    = 1,
+                       .buf    = &start,
+               }, {
+                       .addr   = DDC_ADDR,
+                       .flags  = I2C_M_RD,
+                       .len    = EDID_LENGTH,
+                       .buf    = buf,
+               }
+       };
+
+       if (!buf) {
+               dev_warn(&adapter->dev, "unable to allocate memory for EDID "
+                        "block.\n");
+               return NULL;
+       }
+
+       if (i2c_transfer(adapter, msgs, 2) == 2)
+               return buf;
+
+       dev_warn(&adapter->dev, "unable to read EDID block.\n");
+       kfree(buf);
+       return NULL;
+}
+
+unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
+{
+       struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+       unsigned char *edid = NULL;
+       int i, j;
+
+       algo_data->setscl(algo_data->data, 1);
+
+       for (i = 0; i < 3; i++) {
+               /* For some old monitors we need the
+                * following process to initialize/stop DDC
+                */
+               algo_data->setsda(algo_data->data, 1);
+               msleep(13);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 5; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+               if (j == 5)
+                       continue;
+
+               algo_data->setsda(algo_data->data, 0);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+
+               /* Do the real work */
+               edid = fb_do_probe_ddc_edid(adapter);
+               algo_data->setsda(algo_data->data, 0);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 10; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               algo_data->setsda(algo_data->data, 0);
+               if (edid)
+                       break;
+       }
+       /* Release the DDC lines when done or the Apple Cinema HD display
+        * will switch off
+        */
+       algo_data->setsda(algo_data->data, 1);
+       algo_data->setscl(algo_data->data, 1);
+
+       adapter->class |= I2C_CLASS_DDC;
+       return edid;
+}
+
+EXPORT_SYMBOL_GPL(fb_ddc_read);
+
+MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
+MODULE_DESCRIPTION("DDC/EDID reading support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
new file mode 100644 (file)
index 0000000..900aa4e
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *  linux/drivers/video/fb_defio.c
+ *
+ *  Copyright (C) 2006 Jaya Kumar
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/list.h>
+
+/* to support deferred IO */
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
+
+static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
+{
+       void *screen_base = (void __force *) info->screen_base;
+       struct page *page;
+
+       if (is_vmalloc_addr(screen_base + offs))
+               page = vmalloc_to_page(screen_base + offs);
+       else
+               page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT);
+
+       return page;
+}
+
+/* this is to find and return the vmalloc-ed fb pages */
+static int fb_deferred_io_fault(struct vm_area_struct *vma,
+                               struct vm_fault *vmf)
+{
+       unsigned long offset;
+       struct page *page;
+       struct fb_info *info = vma->vm_private_data;
+
+       offset = vmf->pgoff << PAGE_SHIFT;
+       if (offset >= info->fix.smem_len)
+               return VM_FAULT_SIGBUS;
+
+       page = fb_deferred_io_page(info, offset);
+       if (!page)
+               return VM_FAULT_SIGBUS;
+
+       get_page(page);
+
+       if (vma->vm_file)
+               page->mapping = vma->vm_file->f_mapping;
+       else
+               printk(KERN_ERR "no mapping available\n");
+
+       BUG_ON(!page->mapping);
+       page->index = vmf->pgoff;
+
+       vmf->page = page;
+       return 0;
+}
+
+int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+       struct fb_info *info = file->private_data;
+       struct inode *inode = file_inode(file);
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       /* Skip if deferred io is compiled-in but disabled on this fbdev */
+       if (!info->fbdefio)
+               return 0;
+
+       mutex_lock(&inode->i_mutex);
+       /* Kill off the delayed work */
+       cancel_delayed_work_sync(&info->deferred_work);
+
+       /* Run it immediately */
+       err = schedule_delayed_work(&info->deferred_work, 0);
+       mutex_unlock(&inode->i_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
+
+/* vm_ops->page_mkwrite handler */
+static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
+                                 struct vm_fault *vmf)
+{
+       struct page *page = vmf->page;
+       struct fb_info *info = vma->vm_private_data;
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct page *cur;
+
+       /* this is a callback we get when userspace first tries to
+       write to the page. we schedule a workqueue. that workqueue
+       will eventually mkclean the touched pages and execute the
+       deferred framebuffer IO. then if userspace touches a page
+       again, we repeat the same scheme */
+
+       file_update_time(vma->vm_file);
+
+       /* protect against the workqueue changing the page list */
+       mutex_lock(&fbdefio->lock);
+
+       /* first write in this cycle, notify the driver */
+       if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
+               fbdefio->first_io(info);
+
+       /*
+        * We want the page to remain locked from ->page_mkwrite until
+        * the PTE is marked dirty to avoid page_mkclean() being called
+        * before the PTE is updated, which would leave the page ignored
+        * by defio.
+        * Do this by locking the page here and informing the caller
+        * about it with VM_FAULT_LOCKED.
+        */
+       lock_page(page);
+
+       /* we loop through the pagelist before adding in order
+       to keep the pagelist sorted */
+       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+               /* this check is to catch the case where a new
+               process could start writing to the same page
+               through a new pte. this new access can cause the
+               mkwrite even when the original ps's pte is marked
+               writable */
+               if (unlikely(cur == page))
+                       goto page_already_added;
+               else if (cur->index > page->index)
+                       break;
+       }
+
+       list_add_tail(&page->lru, &cur->lru);
+
+page_already_added:
+       mutex_unlock(&fbdefio->lock);
+
+       /* come back after delay to process the deferred IO */
+       schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+       return VM_FAULT_LOCKED;
+}
+
+static const struct vm_operations_struct fb_deferred_io_vm_ops = {
+       .fault          = fb_deferred_io_fault,
+       .page_mkwrite   = fb_deferred_io_mkwrite,
+};
+
+static int fb_deferred_io_set_page_dirty(struct page *page)
+{
+       if (!PageDirty(page))
+               SetPageDirty(page);
+       return 0;
+}
+
+static const struct address_space_operations fb_deferred_io_aops = {
+       .set_page_dirty = fb_deferred_io_set_page_dirty,
+};
+
+static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       vma->vm_ops = &fb_deferred_io_vm_ops;
+       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       if (!(info->flags & FBINFO_VIRTFB))
+               vma->vm_flags |= VM_IO;
+       vma->vm_private_data = info;
+       return 0;
+}
+
+/* workqueue callback */
+static void fb_deferred_io_work(struct work_struct *work)
+{
+       struct fb_info *info = container_of(work, struct fb_info,
+                                               deferred_work.work);
+       struct list_head *node, *next;
+       struct page *cur;
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+
+       /* here we mkclean the pages, then do all deferred IO */
+       mutex_lock(&fbdefio->lock);
+       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+               lock_page(cur);
+               page_mkclean(cur);
+               unlock_page(cur);
+       }
+
+       /* driver's callback with pagelist */
+       fbdefio->deferred_io(info, &fbdefio->pagelist);
+
+       /* clear the list */
+       list_for_each_safe(node, next, &fbdefio->pagelist) {
+               list_del(node);
+       }
+       mutex_unlock(&fbdefio->lock);
+}
+
+void fb_deferred_io_init(struct fb_info *info)
+{
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+
+       BUG_ON(!fbdefio);
+       mutex_init(&fbdefio->lock);
+       info->fbops->fb_mmap = fb_deferred_io_mmap;
+       INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
+       INIT_LIST_HEAD(&fbdefio->pagelist);
+       if (fbdefio->delay == 0) /* set a default of 1 s */
+               fbdefio->delay = HZ;
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_init);
+
+void fb_deferred_io_open(struct fb_info *info,
+                        struct inode *inode,
+                        struct file *file)
+{
+       file->f_mapping->a_ops = &fb_deferred_io_aops;
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_open);
+
+void fb_deferred_io_cleanup(struct fb_info *info)
+{
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct page *page;
+       int i;
+
+       BUG_ON(!fbdefio);
+       cancel_delayed_work_sync(&info->deferred_work);
+
+       /* clear out the mapping that we setup */
+       for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
+               page = fb_deferred_io_page(info, i);
+               page->mapping = NULL;
+       }
+
+       info->fbops->fb_mmap = NULL;
+       mutex_destroy(&fbdefio->lock);
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/fb_draw.h b/drivers/video/fbdev/core/fb_draw.h
new file mode 100644 (file)
index 0000000..624ee11
--- /dev/null
@@ -0,0 +1,186 @@
+#ifndef _FB_DRAW_H
+#define _FB_DRAW_H
+
+#include <asm/types.h>
+#include <linux/fb.h>
+#include <linux/bug.h>
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+    return ((a ^ b) & mask) ^ b;
+}
+
+    /*
+     *  Create a pattern with the given pixel's color
+     */
+
+#if BITS_PER_LONG == 64
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+       switch (bpp) {
+       case 1:
+               return 0xfffffffffffffffful*pixel;
+       case 2:
+               return 0x5555555555555555ul*pixel;
+       case 4:
+               return 0x1111111111111111ul*pixel;
+       case 8:
+               return 0x0101010101010101ul*pixel;
+       case 12:
+               return 0x1001001001001001ul*pixel;
+       case 16:
+               return 0x0001000100010001ul*pixel;
+       case 24:
+               return 0x0001000001000001ul*pixel;
+       case 32:
+               return 0x0000000100000001ul*pixel;
+       default:
+               WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp);
+               return 0;
+    }
+}
+#else
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+       switch (bpp) {
+       case 1:
+               return 0xfffffffful*pixel;
+       case 2:
+               return 0x55555555ul*pixel;
+       case 4:
+               return 0x11111111ul*pixel;
+       case 8:
+               return 0x01010101ul*pixel;
+       case 12:
+               return 0x01001001ul*pixel;
+       case 16:
+               return 0x00010001ul*pixel;
+       case 24:
+               return 0x01000001ul*pixel;
+       case 32:
+               return 0x00000001ul*pixel;
+       default:
+               WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp);
+               return 0;
+    }
+}
+#endif
+
+#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
+#if BITS_PER_LONG == 64
+#define REV_PIXELS_MASK1 0x5555555555555555ul
+#define REV_PIXELS_MASK2 0x3333333333333333ul
+#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful
+#else
+#define REV_PIXELS_MASK1 0x55555555ul
+#define REV_PIXELS_MASK2 0x33333333ul
+#define REV_PIXELS_MASK4 0x0f0f0f0ful
+#endif
+
+static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
+                                                 u32 bswapmask)
+{
+       if (bswapmask & 1)
+               val = comp(val >> 1, val << 1, REV_PIXELS_MASK1);
+       if (bswapmask & 2)
+               val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
+       if (bswapmask & 3)
+               val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+       return val;
+}
+
+static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index,
+                                            u32 bswapmask)
+{
+       u32 mask;
+
+       if (!bswapmask) {
+               mask = FB_SHIFT_HIGH(p, ~(u32)0, index);
+       } else {
+               mask = 0xff << FB_LEFT_POS(p, 8);
+               mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
+               mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
+#if defined(__i386__) || defined(__x86_64__)
+               /* Shift argument is limited to 0 - 31 on x86 based CPU's */
+               if(index + bswapmask < 32)
+#endif
+                       mask |= FB_SHIFT_HIGH(p, ~(u32)0,
+                                       (index + bswapmask) & ~(bswapmask));
+       }
+       return mask;
+}
+
+static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p,
+                                                       u32 index,
+                                                       u32 bswapmask)
+{
+       unsigned long mask;
+
+       if (!bswapmask) {
+               mask = FB_SHIFT_HIGH(p, ~0UL, index);
+       } else {
+               mask = 0xff << FB_LEFT_POS(p, 8);
+               mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
+               mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
+#if defined(__i386__) || defined(__x86_64__)
+               /* Shift argument is limited to 0 - 31 on x86 based CPU's */
+               if(index + bswapmask < BITS_PER_LONG)
+#endif
+                       mask |= FB_SHIFT_HIGH(p, ~0UL,
+                                       (index + bswapmask) & ~(bswapmask));
+       }
+       return mask;
+}
+
+
+static inline u32 fb_compute_bswapmask(struct fb_info *info)
+{
+       u32 bswapmask = 0;
+       unsigned bpp = info->var.bits_per_pixel;
+
+       if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) {
+               /*
+                * Reversed order of pixel layout in bytes
+                * works only for 1, 2 and 4 bpp
+                */
+               bswapmask = 7 - bpp + 1;
+       }
+       return bswapmask;
+}
+
+#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
+
+static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
+                                                 u32 bswapmask)
+{
+       return val;
+}
+
+#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i))
+#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i))
+#define fb_compute_bswapmask(...) 0
+
+#endif  /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
+
+#define cpu_to_le_long _cpu_to_le_long(BITS_PER_LONG)
+#define _cpu_to_le_long(x) __cpu_to_le_long(x)
+#define __cpu_to_le_long(x) cpu_to_le##x
+
+#define le_long_to_cpu _le_long_to_cpu(BITS_PER_LONG)
+#define _le_long_to_cpu(x) __le_long_to_cpu(x)
+#define __le_long_to_cpu(x) le##x##_to_cpu
+
+static inline unsigned long rolx(unsigned long word, unsigned int shift, unsigned int x)
+{
+       return (word << shift) | (word >> (x - shift));
+}
+
+#endif /* FB_DRAW_H */
diff --git a/drivers/video/fbdev/core/fb_notify.c b/drivers/video/fbdev/core/fb_notify.c
new file mode 100644 (file)
index 0000000..74c2da5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  linux/drivers/video/fb_notify.c
+ *
+ *  Copyright (C) 2006 Antonino Daplas <adaplas@pol.net>
+ *
+ *     2001 - Documented with DocBook
+ *     - Brad Douglas <brad@neruo.com>
+ *
+ * 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.
+ */
+#include <linux/fb.h>
+#include <linux/notifier.h>
+#include <linux/export.h>
+
+static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
+
+/**
+ *     fb_register_client - register a client notifier
+ *     @nb: notifier block to callback on events
+ */
+int fb_register_client(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_register_client);
+
+/**
+ *     fb_unregister_client - unregister a client notifier
+ *     @nb: notifier block to callback on events
+ */
+int fb_unregister_client(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_unregister_client);
+
+/**
+ * fb_notifier_call_chain - notify clients of fb_events
+ *
+ */
+int fb_notifier_call_chain(unsigned long val, void *v)
+{
+       return blocking_notifier_call_chain(&fb_notifier_list, val, v);
+}
+EXPORT_SYMBOL_GPL(fb_notifier_call_chain);
diff --git a/drivers/video/fbdev/core/fb_sys_fops.c b/drivers/video/fbdev/core/fb_sys_fops.c
new file mode 100644 (file)
index 0000000..ff275d7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * linux/drivers/video/fb_sys_read.c - Generic file operations where
+ * framebuffer is in system RAM
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * 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.
+ *
+ */
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
+                   loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *src;
+       int err = 0;
+       unsigned long total_size;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p >= total_size)
+               return 0;
+
+       if (count >= total_size)
+               count = total_size;
+
+       if (count + p > total_size)
+               count = total_size - p;
+
+       src = (void __force *)(info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       if (copy_to_user(buf, src, count))
+               err = -EFAULT;
+
+       if  (!err)
+               *ppos += count;
+
+       return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_read);
+
+ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
+                    size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *dst;
+       int err = 0;
+       unsigned long total_size;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p > total_size)
+               return -EFBIG;
+
+       if (count > total_size) {
+               err = -EFBIG;
+               count = total_size;
+       }
+
+       if (count + p > total_size) {
+               if (!err)
+                       err = -ENOSPC;
+
+               count = total_size - p;
+       }
+
+       dst = (void __force *) (info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       if (copy_from_user(dst, buf, count))
+               err = -EFAULT;
+
+       if  (!err)
+               *ppos += count;
+
+       return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_write);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic file read (fb in system RAM)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
new file mode 100644 (file)
index 0000000..f89245b
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ *  linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
+ *
+ *     Created 15 Jun 1997 by Geert Uytterhoeven
+ *
+ *     2001 - Documented with DocBook
+ *     - Brad Douglas <brad@neruo.com>
+ *
+ *  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.
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+static u16 red2[] __read_mostly = {
+    0x0000, 0xaaaa
+};
+static u16 green2[] __read_mostly = {
+    0x0000, 0xaaaa
+};
+static u16 blue2[] __read_mostly = {
+    0x0000, 0xaaaa
+};
+
+static u16 red4[] __read_mostly = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+static u16 green4[] __read_mostly = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+static u16 blue4[] __read_mostly = {
+    0x0000, 0xaaaa, 0x5555, 0xffff
+};
+
+static u16 red8[] __read_mostly = {
+    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
+};
+static u16 green8[] __read_mostly = {
+    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
+};
+static u16 blue8[] __read_mostly = {
+    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
+};
+
+static u16 red16[] __read_mostly = {
+    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
+    0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
+};
+static u16 green16[] __read_mostly = {
+    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
+    0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
+};
+static u16 blue16[] __read_mostly = {
+    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
+    0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
+};
+
+static const struct fb_cmap default_2_colors = {
+    .len=2, .red=red2, .green=green2, .blue=blue2
+};
+static const struct fb_cmap default_8_colors = {
+    .len=8, .red=red8, .green=green8, .blue=blue8
+};
+static const struct fb_cmap default_4_colors = {
+    .len=4, .red=red4, .green=green4, .blue=blue4
+};
+static const struct fb_cmap default_16_colors = {
+    .len=16, .red=red16, .green=green16, .blue=blue16
+};
+
+
+
+/**
+ *     fb_alloc_cmap - allocate a colormap
+ *     @cmap: frame buffer colormap structure
+ *     @len: length of @cmap
+ *     @transp: boolean, 1 if there is transparency, 0 otherwise
+ *     @flags: flags for kmalloc memory allocation
+ *
+ *     Allocates memory for a colormap @cmap.  @len is the
+ *     number of entries in the palette.
+ *
+ *     Returns negative errno on error, or zero on success.
+ *
+ */
+
+int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
+{
+       int size = len * sizeof(u16);
+       int ret = -ENOMEM;
+
+       if (cmap->len != len) {
+               fb_dealloc_cmap(cmap);
+               if (!len)
+                       return 0;
+
+               cmap->red = kmalloc(size, flags);
+               if (!cmap->red)
+                       goto fail;
+               cmap->green = kmalloc(size, flags);
+               if (!cmap->green)
+                       goto fail;
+               cmap->blue = kmalloc(size, flags);
+               if (!cmap->blue)
+                       goto fail;
+               if (transp) {
+                       cmap->transp = kmalloc(size, flags);
+                       if (!cmap->transp)
+                               goto fail;
+               } else {
+                       cmap->transp = NULL;
+               }
+       }
+       cmap->start = 0;
+       cmap->len = len;
+       ret = fb_copy_cmap(fb_default_cmap(len), cmap);
+       if (ret)
+               goto fail;
+       return 0;
+
+fail:
+       fb_dealloc_cmap(cmap);
+       return ret;
+}
+
+int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
+{
+       return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
+}
+
+/**
+ *      fb_dealloc_cmap - deallocate a colormap
+ *      @cmap: frame buffer colormap structure
+ *
+ *      Deallocates a colormap that was previously allocated with
+ *      fb_alloc_cmap().
+ *
+ */
+
+void fb_dealloc_cmap(struct fb_cmap *cmap)
+{
+       kfree(cmap->red);
+       kfree(cmap->green);
+       kfree(cmap->blue);
+       kfree(cmap->transp);
+
+       cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
+       cmap->len = 0;
+}
+
+/**
+ *     fb_copy_cmap - copy a colormap
+ *     @from: frame buffer colormap structure
+ *     @to: frame buffer colormap structure
+ *
+ *     Copy contents of colormap from @from to @to.
+ */
+
+int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
+{
+       int tooff = 0, fromoff = 0;
+       int size;
+
+       if (to->start > from->start)
+               fromoff = to->start - from->start;
+       else
+               tooff = from->start - to->start;
+       size = to->len - tooff;
+       if (size > (int) (from->len - fromoff))
+               size = from->len - fromoff;
+       if (size <= 0)
+               return -EINVAL;
+       size *= sizeof(u16);
+
+       memcpy(to->red+tooff, from->red+fromoff, size);
+       memcpy(to->green+tooff, from->green+fromoff, size);
+       memcpy(to->blue+tooff, from->blue+fromoff, size);
+       if (from->transp && to->transp)
+               memcpy(to->transp+tooff, from->transp+fromoff, size);
+       return 0;
+}
+
+int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
+{
+       int tooff = 0, fromoff = 0;
+       int size;
+
+       if (to->start > from->start)
+               fromoff = to->start - from->start;
+       else
+               tooff = from->start - to->start;
+       size = to->len - tooff;
+       if (size > (int) (from->len - fromoff))
+               size = from->len - fromoff;
+       if (size <= 0)
+               return -EINVAL;
+       size *= sizeof(u16);
+
+       if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+               return -EFAULT;
+       if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+               return -EFAULT;
+       if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+               return -EFAULT;
+       if (from->transp && to->transp)
+               if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
+                       return -EFAULT;
+       return 0;
+}
+
+/**
+ *     fb_set_cmap - set the colormap
+ *     @cmap: frame buffer colormap structure
+ *     @info: frame buffer info structure
+ *
+ *     Sets the colormap @cmap for a screen of device @info.
+ *
+ *     Returns negative errno on error, or zero on success.
+ *
+ */
+
+int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+       int i, start, rc = 0;
+       u16 *red, *green, *blue, *transp;
+       u_int hred, hgreen, hblue, htransp = 0xffff;
+
+       red = cmap->red;
+       green = cmap->green;
+       blue = cmap->blue;
+       transp = cmap->transp;
+       start = cmap->start;
+
+       if (start < 0 || (!info->fbops->fb_setcolreg &&
+                         !info->fbops->fb_setcmap))
+               return -EINVAL;
+       if (info->fbops->fb_setcmap) {
+               rc = info->fbops->fb_setcmap(cmap, info);
+       } else {
+               for (i = 0; i < cmap->len; i++) {
+                       hred = *red++;
+                       hgreen = *green++;
+                       hblue = *blue++;
+                       if (transp)
+                               htransp = *transp++;
+                       if (info->fbops->fb_setcolreg(start++,
+                                                     hred, hgreen, hblue,
+                                                     htransp, info))
+                               break;
+               }
+       }
+       if (rc == 0)
+               fb_copy_cmap(cmap, &info->cmap);
+
+       return rc;
+}
+
+int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
+{
+       int rc, size = cmap->len * sizeof(u16);
+       struct fb_cmap umap;
+
+       if (size < 0 || size < cmap->len)
+               return -E2BIG;
+
+       memset(&umap, 0, sizeof(struct fb_cmap));
+       rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
+                               GFP_KERNEL);
+       if (rc)
+               return rc;
+       if (copy_from_user(umap.red, cmap->red, size) ||
+           copy_from_user(umap.green, cmap->green, size) ||
+           copy_from_user(umap.blue, cmap->blue, size) ||
+           (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) {
+               rc = -EFAULT;
+               goto out;
+       }
+       umap.start = cmap->start;
+       if (!lock_fb_info(info)) {
+               rc = -ENODEV;
+               goto out;
+       }
+
+       rc = fb_set_cmap(&umap, info);
+       unlock_fb_info(info);
+out:
+       fb_dealloc_cmap(&umap);
+       return rc;
+}
+
+/**
+ *     fb_default_cmap - get default colormap
+ *     @len: size of palette for a depth
+ *
+ *     Gets the default colormap for a specific screen depth.  @len
+ *     is the size of the palette for a particular screen depth.
+ *
+ *     Returns pointer to a frame buffer colormap structure.
+ *
+ */
+
+const struct fb_cmap *fb_default_cmap(int len)
+{
+    if (len <= 2)
+       return &default_2_colors;
+    if (len <= 4)
+       return &default_4_colors;
+    if (len <= 8)
+       return &default_8_colors;
+    return &default_16_colors;
+}
+
+
+/**
+ *     fb_invert_cmaps - invert all defaults colormaps
+ *
+ *     Invert all default colormaps.
+ *
+ */
+
+void fb_invert_cmaps(void)
+{
+    u_int i;
+
+    for (i = 0; i < ARRAY_SIZE(red2); i++) {
+       red2[i] = ~red2[i];
+       green2[i] = ~green2[i];
+       blue2[i] = ~blue2[i];
+    }
+    for (i = 0; i < ARRAY_SIZE(red4); i++) {
+       red4[i] = ~red4[i];
+       green4[i] = ~green4[i];
+       blue4[i] = ~blue4[i];
+    }
+    for (i = 0; i < ARRAY_SIZE(red8); i++) {
+       red8[i] = ~red8[i];
+       green8[i] = ~green8[i];
+       blue8[i] = ~blue8[i];
+    }
+    for (i = 0; i < ARRAY_SIZE(red16); i++) {
+       red16[i] = ~red16[i];
+       green16[i] = ~green16[i];
+       blue16[i] = ~blue16[i];
+    }
+}
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fb_alloc_cmap);
+EXPORT_SYMBOL(fb_dealloc_cmap);
+EXPORT_SYMBOL(fb_copy_cmap);
+EXPORT_SYMBOL(fb_set_cmap);
+EXPORT_SYMBOL(fb_default_cmap);
+EXPORT_SYMBOL(fb_invert_cmaps);
diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c
new file mode 100644 (file)
index 0000000..7cb715d
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * linux/drivers/video/fbcvt.c - VESA(TM) Coordinated Video Timings
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
+ *
+ *      Based from the VESA(TM) Coordinated Video Timing Generator by
+ *      Graham Loveridge April 9, 2003 available at
+ *      http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
+ *
+ * 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.
+ *
+ */
+#include <linux/fb.h>
+#include <linux/slab.h>
+
+#define FB_CVT_CELLSIZE               8
+#define FB_CVT_GTF_C                 40
+#define FB_CVT_GTF_J                 20
+#define FB_CVT_GTF_K                128
+#define FB_CVT_GTF_M                600
+#define FB_CVT_MIN_VSYNC_BP         550
+#define FB_CVT_MIN_VPORCH             3
+#define FB_CVT_MIN_BPORCH             6
+
+#define FB_CVT_RB_MIN_VBLANK        460
+#define FB_CVT_RB_HBLANK            160
+#define FB_CVT_RB_V_FPORCH            3
+
+#define FB_CVT_FLAG_REDUCED_BLANK 1
+#define FB_CVT_FLAG_MARGINS       2
+#define FB_CVT_FLAG_INTERLACED    4
+
+struct fb_cvt_data {
+       u32 xres;
+       u32 yres;
+       u32 refresh;
+       u32 f_refresh;
+       u32 pixclock;
+       u32 hperiod;
+       u32 hblank;
+       u32 hfreq;
+       u32 htotal;
+       u32 vtotal;
+       u32 vsync;
+       u32 hsync;
+       u32 h_front_porch;
+       u32 h_back_porch;
+       u32 v_front_porch;
+       u32 v_back_porch;
+       u32 h_margin;
+       u32 v_margin;
+       u32 interlace;
+       u32 aspect_ratio;
+       u32 active_pixels;
+       u32 flags;
+       u32 status;
+};
+
+static const unsigned char fb_cvt_vbi_tab[] = {
+       4,        /* 4:3      */
+       5,        /* 16:9     */
+       6,        /* 16:10    */
+       7,        /* 5:4      */
+       7,        /* 15:9     */
+       8,        /* reserved */
+       9,        /* reserved */
+       10        /* custom   */
+};
+
+/* returns hperiod * 1000 */
+static u32 fb_cvt_hperiod(struct fb_cvt_data *cvt)
+{
+       u32 num = 1000000000/cvt->f_refresh;
+       u32 den;
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
+               num -= FB_CVT_RB_MIN_VBLANK * 1000;
+               den = 2 * (cvt->yres/cvt->interlace + 2 * cvt->v_margin);
+       } else {
+               num -= FB_CVT_MIN_VSYNC_BP * 1000;
+               den = 2 * (cvt->yres/cvt->interlace + cvt->v_margin * 2
+                          + FB_CVT_MIN_VPORCH + cvt->interlace/2);
+       }
+
+       return 2 * (num/den);
+}
+
+/* returns ideal duty cycle * 1000 */
+static u32 fb_cvt_ideal_duty_cycle(struct fb_cvt_data *cvt)
+{
+       u32 c_prime = (FB_CVT_GTF_C - FB_CVT_GTF_J) *
+               (FB_CVT_GTF_K) + 256 * FB_CVT_GTF_J;
+       u32 m_prime = (FB_CVT_GTF_K * FB_CVT_GTF_M);
+       u32 h_period_est = cvt->hperiod;
+
+       return (1000 * c_prime  - ((m_prime * h_period_est)/1000))/256;
+}
+
+static u32 fb_cvt_hblank(struct fb_cvt_data *cvt)
+{
+       u32 hblank = 0;
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
+               hblank = FB_CVT_RB_HBLANK;
+       else {
+               u32 ideal_duty_cycle = fb_cvt_ideal_duty_cycle(cvt);
+               u32 active_pixels = cvt->active_pixels;
+
+               if (ideal_duty_cycle < 20000)
+                       hblank = (active_pixels * 20000)/
+                               (100000 - 20000);
+               else {
+                       hblank = (active_pixels * ideal_duty_cycle)/
+                               (100000 - ideal_duty_cycle);
+               }
+       }
+
+       hblank &= ~((2 * FB_CVT_CELLSIZE) - 1);
+
+       return hblank;
+}
+
+static u32 fb_cvt_hsync(struct fb_cvt_data *cvt)
+{
+       u32 hsync;
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
+               hsync = 32;
+       else
+               hsync = (FB_CVT_CELLSIZE * cvt->htotal)/100;
+
+       hsync &= ~(FB_CVT_CELLSIZE - 1);
+       return hsync;
+}
+
+static u32 fb_cvt_vbi_lines(struct fb_cvt_data *cvt)
+{
+       u32 vbi_lines, min_vbi_lines, act_vbi_lines;
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
+               vbi_lines = (1000 * FB_CVT_RB_MIN_VBLANK)/cvt->hperiod + 1;
+               min_vbi_lines =  FB_CVT_RB_V_FPORCH + cvt->vsync +
+                       FB_CVT_MIN_BPORCH;
+
+       } else {
+               vbi_lines = (FB_CVT_MIN_VSYNC_BP * 1000)/cvt->hperiod + 1 +
+                        FB_CVT_MIN_VPORCH;
+               min_vbi_lines = cvt->vsync + FB_CVT_MIN_BPORCH +
+                       FB_CVT_MIN_VPORCH;
+       }
+
+       if (vbi_lines < min_vbi_lines)
+               act_vbi_lines = min_vbi_lines;
+       else
+               act_vbi_lines = vbi_lines;
+
+       return act_vbi_lines;
+}
+
+static u32 fb_cvt_vtotal(struct fb_cvt_data *cvt)
+{
+       u32 vtotal = cvt->yres/cvt->interlace;
+
+       vtotal += 2 * cvt->v_margin + cvt->interlace/2 + fb_cvt_vbi_lines(cvt);
+       vtotal |= cvt->interlace/2;
+
+       return vtotal;
+}
+
+static u32 fb_cvt_pixclock(struct fb_cvt_data *cvt)
+{
+       u32 pixclock;
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
+               pixclock = (cvt->f_refresh * cvt->vtotal * cvt->htotal)/1000;
+       else
+               pixclock = (cvt->htotal * 1000000)/cvt->hperiod;
+
+       pixclock /= 250;
+       pixclock *= 250;
+       pixclock *= 1000;
+
+       return pixclock;
+}
+
+static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt)
+{
+       u32 xres = cvt->xres;
+       u32 yres = cvt->yres;
+       u32 aspect = -1;
+
+       if (xres == (yres * 4)/3 && !((yres * 4) % 3))
+               aspect = 0;
+       else if (xres == (yres * 16)/9 && !((yres * 16) % 9))
+               aspect = 1;
+       else if (xres == (yres * 16)/10 && !((yres * 16) % 10))
+               aspect = 2;
+       else if (xres == (yres * 5)/4 && !((yres * 5) % 4))
+               aspect = 3;
+       else if (xres == (yres * 15)/9 && !((yres * 15) % 9))
+               aspect = 4;
+       else {
+               printk(KERN_INFO "fbcvt: Aspect ratio not CVT "
+                      "standard\n");
+               aspect = 7;
+               cvt->status = 1;
+       }
+
+       return aspect;
+}
+
+static void fb_cvt_print_name(struct fb_cvt_data *cvt)
+{
+       u32 pixcount, pixcount_mod;
+       int cnt = 255, offset = 0, read = 0;
+       u8 *buf = kzalloc(256, GFP_KERNEL);
+
+       if (!buf)
+               return;
+
+       pixcount = (cvt->xres * (cvt->yres/cvt->interlace))/1000000;
+       pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000;
+       pixcount_mod /= 1000;
+
+       read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ",
+                       cvt->xres, cvt->yres, cvt->refresh);
+       offset += read;
+       cnt -= read;
+
+       if (cvt->status)
+               snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega "
+                        "Pixel Image\n", pixcount, pixcount_mod);
+       else {
+               if (pixcount) {
+                       read = snprintf(buf+offset, cnt, "%d", pixcount);
+                       cnt -= read;
+                       offset += read;
+               }
+
+               read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod);
+               cnt -= read;
+               offset += read;
+
+               if (cvt->aspect_ratio == 0)
+                       read = snprintf(buf+offset, cnt, "3");
+               else if (cvt->aspect_ratio == 3)
+                       read = snprintf(buf+offset, cnt, "4");
+               else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4)
+                       read = snprintf(buf+offset, cnt, "9");
+               else if (cvt->aspect_ratio == 2)
+                       read = snprintf(buf+offset, cnt, "A");
+               else
+                       read = 0;
+               cnt -= read;
+               offset += read;
+
+               if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
+                       read = snprintf(buf+offset, cnt, "-R");
+                       cnt -= read;
+                       offset += read;
+               }
+       }
+
+       printk(KERN_INFO "%s\n", buf);
+       kfree(buf);
+}
+
+static void fb_cvt_convert_to_mode(struct fb_cvt_data *cvt,
+                                  struct fb_videomode *mode)
+{
+       mode->refresh = cvt->f_refresh;
+       mode->pixclock = KHZ2PICOS(cvt->pixclock/1000);
+       mode->left_margin = cvt->h_back_porch;
+       mode->right_margin = cvt->h_front_porch;
+       mode->hsync_len = cvt->hsync;
+       mode->upper_margin = cvt->v_back_porch;
+       mode->lower_margin = cvt->v_front_porch;
+       mode->vsync_len = cvt->vsync;
+
+       mode->sync &= ~(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT);
+
+       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
+               mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+       else
+               mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+}
+
+/*
+ * fb_find_mode_cvt - calculate mode using VESA(TM) CVT
+ * @mode: pointer to fb_videomode; xres, yres, refresh and vmode must be
+ *        pre-filled with the desired values
+ * @margins: add margin to calculation (1.8% of xres and yres)
+ * @rb: compute with reduced blanking (for flatpanels)
+ *
+ * RETURNS:
+ * 0 for success
+ * @mode is filled with computed values.  If interlaced, the refresh field
+ * will be filled with the field rate (2x the frame rate)
+ *
+ * DESCRIPTION:
+ * Computes video timings using VESA(TM) Coordinated Video Timings
+ */
+int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb)
+{
+       struct fb_cvt_data cvt;
+
+       memset(&cvt, 0, sizeof(cvt));
+
+       if (margins)
+           cvt.flags |= FB_CVT_FLAG_MARGINS;
+
+       if (rb)
+           cvt.flags |= FB_CVT_FLAG_REDUCED_BLANK;
+
+       if (mode->vmode & FB_VMODE_INTERLACED)
+           cvt.flags |= FB_CVT_FLAG_INTERLACED;
+
+       cvt.xres = mode->xres;
+       cvt.yres = mode->yres;
+       cvt.refresh = mode->refresh;
+       cvt.f_refresh = cvt.refresh;
+       cvt.interlace = 1;
+
+       if (!cvt.xres || !cvt.yres || !cvt.refresh) {
+               printk(KERN_INFO "fbcvt: Invalid input parameters\n");
+               return 1;
+       }
+
+       if (!(cvt.refresh == 50 || cvt.refresh == 60 || cvt.refresh == 70 ||
+             cvt.refresh == 85)) {
+               printk(KERN_INFO "fbcvt: Refresh rate not CVT "
+                      "standard\n");
+               cvt.status = 1;
+       }
+
+       cvt.xres &= ~(FB_CVT_CELLSIZE - 1);
+
+       if (cvt.flags & FB_CVT_FLAG_INTERLACED) {
+               cvt.interlace = 2;
+               cvt.f_refresh *= 2;
+       }
+
+       if (cvt.flags & FB_CVT_FLAG_REDUCED_BLANK) {
+               if (cvt.refresh != 60) {
+                       printk(KERN_INFO "fbcvt: 60Hz refresh rate "
+                              "advised for reduced blanking\n");
+                       cvt.status = 1;
+               }
+       }
+
+       if (cvt.flags & FB_CVT_FLAG_MARGINS) {
+               cvt.h_margin = (cvt.xres * 18)/1000;
+               cvt.h_margin &= ~(FB_CVT_CELLSIZE - 1);
+               cvt.v_margin = ((cvt.yres/cvt.interlace)* 18)/1000;
+       }
+
+       cvt.aspect_ratio = fb_cvt_aspect_ratio(&cvt);
+       cvt.active_pixels = cvt.xres + 2 * cvt.h_margin;
+       cvt.hperiod = fb_cvt_hperiod(&cvt);
+       cvt.vsync = fb_cvt_vbi_tab[cvt.aspect_ratio];
+       cvt.vtotal = fb_cvt_vtotal(&cvt);
+       cvt.hblank = fb_cvt_hblank(&cvt);
+       cvt.htotal = cvt.active_pixels + cvt.hblank;
+       cvt.hsync = fb_cvt_hsync(&cvt);
+       cvt.pixclock = fb_cvt_pixclock(&cvt);
+       cvt.hfreq = cvt.pixclock/cvt.htotal;
+       cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin;
+       cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch +
+               2 * cvt.h_margin;
+       cvt.v_back_porch = 3 + cvt.v_margin;
+       cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace -
+           cvt.v_back_porch - cvt.vsync;
+       fb_cvt_print_name(&cvt);
+       fb_cvt_convert_to_mode(&cvt, mode);
+
+       return 0;
+}
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
new file mode 100644 (file)
index 0000000..b6d5008
--- /dev/null
@@ -0,0 +1,2002 @@
+/*
+ *  linux/drivers/video/fbmem.c
+ *
+ *  Copyright (C) 1994 Martin Schaller
+ *
+ *     2001 - Documented with DocBook
+ *     - Brad Douglas <brad@neruo.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+
+#include <linux/compat.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/vt.h>
+#include <linux/init.h>
+#include <linux/linux_logo.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/kmod.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+#include <linux/fb.h>
+
+#include <asm/fb.h>
+
+
+    /*
+     *  Frame buffer device initialization and setup routines
+     */
+
+#define FBPIXMAPSIZE   (1024 * 8)
+
+static DEFINE_MUTEX(registration_lock);
+
+struct fb_info *registered_fb[FB_MAX] __read_mostly;
+EXPORT_SYMBOL(registered_fb);
+
+int num_registered_fb __read_mostly;
+EXPORT_SYMBOL(num_registered_fb);
+
+static struct fb_info *get_fb_info(unsigned int idx)
+{
+       struct fb_info *fb_info;
+
+       if (idx >= FB_MAX)
+               return ERR_PTR(-ENODEV);
+
+       mutex_lock(&registration_lock);
+       fb_info = registered_fb[idx];
+       if (fb_info)
+               atomic_inc(&fb_info->count);
+       mutex_unlock(&registration_lock);
+
+       return fb_info;
+}
+
+static void put_fb_info(struct fb_info *fb_info)
+{
+       if (!atomic_dec_and_test(&fb_info->count))
+               return;
+       if (fb_info->fbops->fb_destroy)
+               fb_info->fbops->fb_destroy(fb_info);
+}
+
+int lock_fb_info(struct fb_info *info)
+{
+       mutex_lock(&info->lock);
+       if (!info->fbops) {
+               mutex_unlock(&info->lock);
+               return 0;
+       }
+       return 1;
+}
+EXPORT_SYMBOL(lock_fb_info);
+
+/*
+ * Helpers
+ */
+
+int fb_get_color_depth(struct fb_var_screeninfo *var,
+                      struct fb_fix_screeninfo *fix)
+{
+       int depth = 0;
+
+       if (fix->visual == FB_VISUAL_MONO01 ||
+           fix->visual == FB_VISUAL_MONO10)
+               depth = 1;
+       else {
+               if (var->green.length == var->blue.length &&
+                   var->green.length == var->red.length &&
+                   var->green.offset == var->blue.offset &&
+                   var->green.offset == var->red.offset)
+                       depth = var->green.length;
+               else
+                       depth = var->green.length + var->red.length +
+                               var->blue.length;
+       }
+
+       return depth;
+}
+EXPORT_SYMBOL(fb_get_color_depth);
+
+/*
+ * Data padding functions.
+ */
+void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
+{
+       __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
+}
+EXPORT_SYMBOL(fb_pad_aligned_buffer);
+
+void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
+                               u32 shift_high, u32 shift_low, u32 mod)
+{
+       u8 mask = (u8) (0xfff << shift_high), tmp;
+       int i, j;
+
+       for (i = height; i--; ) {
+               for (j = 0; j < idx; j++) {
+                       tmp = dst[j];
+                       tmp &= mask;
+                       tmp |= *src >> shift_low;
+                       dst[j] = tmp;
+                       tmp = *src << shift_high;
+                       dst[j+1] = tmp;
+                       src++;
+               }
+               tmp = dst[idx];
+               tmp &= mask;
+               tmp |= *src >> shift_low;
+               dst[idx] = tmp;
+               if (shift_high < mod) {
+                       tmp = *src << shift_high;
+                       dst[idx+1] = tmp;
+               }
+               src++;
+               dst += d_pitch;
+       }
+}
+EXPORT_SYMBOL(fb_pad_unaligned_buffer);
+
+/*
+ * we need to lock this section since fb_cursor
+ * may use fb_imageblit()
+ */
+char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
+{
+       u32 align = buf->buf_align - 1, offset;
+       char *addr = buf->addr;
+
+       /* If IO mapped, we need to sync before access, no sharing of
+        * the pixmap is done
+        */
+       if (buf->flags & FB_PIXMAP_IO) {
+               if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
+                       info->fbops->fb_sync(info);
+               return addr;
+       }
+
+       /* See if we fit in the remaining pixmap space */
+       offset = buf->offset + align;
+       offset &= ~align;
+       if (offset + size > buf->size) {
+               /* We do not fit. In order to be able to re-use the buffer,
+                * we must ensure no asynchronous DMA'ing or whatever operation
+                * is in progress, we sync for that.
+                */
+               if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
+                       info->fbops->fb_sync(info);
+               offset = 0;
+       }
+       buf->offset = offset + size;
+       addr += offset;
+
+       return addr;
+}
+EXPORT_SYMBOL(fb_get_buffer_offset);
+
+#ifdef CONFIG_LOGO
+
+static inline unsigned safe_shift(unsigned d, int n)
+{
+       return n < 0 ? d >> -n : d << n;
+}
+
+static void fb_set_logocmap(struct fb_info *info,
+                                  const struct linux_logo *logo)
+{
+       struct fb_cmap palette_cmap;
+       u16 palette_green[16];
+       u16 palette_blue[16];
+       u16 palette_red[16];
+       int i, j, n;
+       const unsigned char *clut = logo->clut;
+
+       palette_cmap.start = 0;
+       palette_cmap.len = 16;
+       palette_cmap.red = palette_red;
+       palette_cmap.green = palette_green;
+       palette_cmap.blue = palette_blue;
+       palette_cmap.transp = NULL;
+
+       for (i = 0; i < logo->clutsize; i += n) {
+               n = logo->clutsize - i;
+               /* palette_cmap provides space for only 16 colors at once */
+               if (n > 16)
+                       n = 16;
+               palette_cmap.start = 32 + i;
+               palette_cmap.len = n;
+               for (j = 0; j < n; ++j) {
+                       palette_cmap.red[j] = clut[0] << 8 | clut[0];
+                       palette_cmap.green[j] = clut[1] << 8 | clut[1];
+                       palette_cmap.blue[j] = clut[2] << 8 | clut[2];
+                       clut += 3;
+               }
+               fb_set_cmap(&palette_cmap, info);
+       }
+}
+
+static void  fb_set_logo_truepalette(struct fb_info *info,
+                                           const struct linux_logo *logo,
+                                           u32 *palette)
+{
+       static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+       unsigned char redmask, greenmask, bluemask;
+       int redshift, greenshift, blueshift;
+       int i;
+       const unsigned char *clut = logo->clut;
+
+       /*
+        * We have to create a temporary palette since console palette is only
+        * 16 colors long.
+        */
+       /* Bug: Doesn't obey msb_right ... (who needs that?) */
+       redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
+       greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
+       bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
+       redshift   = info->var.red.offset   - (8 - info->var.red.length);
+       greenshift = info->var.green.offset - (8 - info->var.green.length);
+       blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
+
+       for ( i = 0; i < logo->clutsize; i++) {
+               palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
+                                safe_shift((clut[1] & greenmask), greenshift) |
+                                safe_shift((clut[2] & bluemask), blueshift));
+               clut += 3;
+       }
+}
+
+static void fb_set_logo_directpalette(struct fb_info *info,
+                                            const struct linux_logo *logo,
+                                            u32 *palette)
+{
+       int redshift, greenshift, blueshift;
+       int i;
+
+       redshift = info->var.red.offset;
+       greenshift = info->var.green.offset;
+       blueshift = info->var.blue.offset;
+
+       for (i = 32; i < 32 + logo->clutsize; i++)
+               palette[i] = i << redshift | i << greenshift | i << blueshift;
+}
+
+static void fb_set_logo(struct fb_info *info,
+                              const struct linux_logo *logo, u8 *dst,
+                              int depth)
+{
+       int i, j, k;
+       const u8 *src = logo->data;
+       u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
+       u8 fg = 1, d;
+
+       switch (fb_get_color_depth(&info->var, &info->fix)) {
+       case 1:
+               fg = 1;
+               break;
+       case 2:
+               fg = 3;
+               break;
+       default:
+               fg = 7;
+               break;
+       }
+
+       if (info->fix.visual == FB_VISUAL_MONO01 ||
+           info->fix.visual == FB_VISUAL_MONO10)
+               fg = ~((u8) (0xfff << info->var.green.length));
+
+       switch (depth) {
+       case 4:
+               for (i = 0; i < logo->height; i++)
+                       for (j = 0; j < logo->width; src++) {
+                               *dst++ = *src >> 4;
+                               j++;
+                               if (j < logo->width) {
+                                       *dst++ = *src & 0x0f;
+                                       j++;
+                               }
+                       }
+               break;
+       case 1:
+               for (i = 0; i < logo->height; i++) {
+                       for (j = 0; j < logo->width; src++) {
+                               d = *src ^ xor;
+                               for (k = 7; k >= 0; k--) {
+                                       *dst++ = ((d >> k) & 1) ? fg : 0;
+                                       j++;
+                               }
+                       }
+               }
+               break;
+       }
+}
+
+/*
+ * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
+ * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
+ * the visual format and color depth of the framebuffer, the DAC, the
+ * pseudo_palette, and the logo data will be adjusted accordingly.
+ *
+ * Case 1 - linux_logo_clut224:
+ * Color exceeds the number of console colors (16), thus we set the hardware DAC
+ * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
+ *
+ * For visuals that require color info from the pseudo_palette, we also construct
+ * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
+ * will be set.
+ *
+ * Case 2 - linux_logo_vga16:
+ * The number of colors just matches the console colors, thus there is no need
+ * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
+ * each byte contains color information for two pixels (upper and lower nibble).
+ * To be consistent with fb_imageblit() usage, we therefore separate the two
+ * nibbles into separate bytes. The "depth" flag will be set to 4.
+ *
+ * Case 3 - linux_logo_mono:
+ * This is similar with Case 2.  Each byte contains information for 8 pixels.
+ * We isolate each bit and expand each into a byte. The "depth" flag will
+ * be set to 1.
+ */
+static struct logo_data {
+       int depth;
+       int needs_directpalette;
+       int needs_truepalette;
+       int needs_cmapreset;
+       const struct linux_logo *logo;
+} fb_logo __read_mostly;
+
+static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       u32 size = width * height, i;
+
+       out += size - 1;
+
+       for (i = size; i--; )
+               *out-- = *in++;
+}
+
+static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       int i, j, h = height - 1;
+
+       for (i = 0; i < height; i++)
+               for (j = 0; j < width; j++)
+                               out[height * j + h - i] = *in++;
+}
+
+static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       int i, j, w = width - 1;
+
+       for (i = 0; i < height; i++)
+               for (j = 0; j < width; j++)
+                       out[height * (w - j) + i] = *in++;
+}
+
+static void fb_rotate_logo(struct fb_info *info, u8 *dst,
+                          struct fb_image *image, int rotate)
+{
+       u32 tmp;
+
+       if (rotate == FB_ROTATE_UD) {
+               fb_rotate_logo_ud(image->data, dst, image->width,
+                                 image->height);
+               image->dx = info->var.xres - image->width - image->dx;
+               image->dy = info->var.yres - image->height - image->dy;
+       } else if (rotate == FB_ROTATE_CW) {
+               fb_rotate_logo_cw(image->data, dst, image->width,
+                                 image->height);
+               tmp = image->width;
+               image->width = image->height;
+               image->height = tmp;
+               tmp = image->dy;
+               image->dy = image->dx;
+               image->dx = info->var.xres - image->width - tmp;
+       } else if (rotate == FB_ROTATE_CCW) {
+               fb_rotate_logo_ccw(image->data, dst, image->width,
+                                  image->height);
+               tmp = image->width;
+               image->width = image->height;
+               image->height = tmp;
+               tmp = image->dx;
+               image->dx = image->dy;
+               image->dy = info->var.yres - image->height - tmp;
+       }
+
+       image->data = dst;
+}
+
+static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
+                           int rotate, unsigned int num)
+{
+       unsigned int x;
+
+       if (rotate == FB_ROTATE_UR) {
+               for (x = 0;
+                    x < num && image->dx + image->width <= info->var.xres;
+                    x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dx += image->width + 8;
+               }
+       } else if (rotate == FB_ROTATE_UD) {
+               for (x = 0; x < num && image->dx >= 0; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dx -= image->width + 8;
+               }
+       } else if (rotate == FB_ROTATE_CW) {
+               for (x = 0;
+                    x < num && image->dy + image->height <= info->var.yres;
+                    x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dy += image->height + 8;
+               }
+       } else if (rotate == FB_ROTATE_CCW) {
+               for (x = 0; x < num && image->dy >= 0; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dy -= image->height + 8;
+               }
+       }
+}
+
+static int fb_show_logo_line(struct fb_info *info, int rotate,
+                            const struct linux_logo *logo, int y,
+                            unsigned int n)
+{
+       u32 *palette = NULL, *saved_pseudo_palette = NULL;
+       unsigned char *logo_new = NULL, *logo_rotate = NULL;
+       struct fb_image image;
+
+       /* Return if the frame buffer is not mapped or suspended */
+       if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+           info->flags & FBINFO_MODULE)
+               return 0;
+
+       image.depth = 8;
+       image.data = logo->data;
+
+       if (fb_logo.needs_cmapreset)
+               fb_set_logocmap(info, logo);
+
+       if (fb_logo.needs_truepalette ||
+           fb_logo.needs_directpalette) {
+               palette = kmalloc(256 * 4, GFP_KERNEL);
+               if (palette == NULL)
+                       return 0;
+
+               if (fb_logo.needs_truepalette)
+                       fb_set_logo_truepalette(info, logo, palette);
+               else
+                       fb_set_logo_directpalette(info, logo, palette);
+
+               saved_pseudo_palette = info->pseudo_palette;
+               info->pseudo_palette = palette;
+       }
+
+       if (fb_logo.depth <= 4) {
+               logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
+               if (logo_new == NULL) {
+                       kfree(palette);
+                       if (saved_pseudo_palette)
+                               info->pseudo_palette = saved_pseudo_palette;
+                       return 0;
+               }
+               image.data = logo_new;
+               fb_set_logo(info, logo, logo_new, fb_logo.depth);
+       }
+
+       image.dx = 0;
+       image.dy = y;
+       image.width = logo->width;
+       image.height = logo->height;
+
+       if (rotate) {
+               logo_rotate = kmalloc(logo->width *
+                                     logo->height, GFP_KERNEL);
+               if (logo_rotate)
+                       fb_rotate_logo(info, logo_rotate, &image, rotate);
+       }
+
+       fb_do_show_logo(info, &image, rotate, n);
+
+       kfree(palette);
+       if (saved_pseudo_palette != NULL)
+               info->pseudo_palette = saved_pseudo_palette;
+       kfree(logo_new);
+       kfree(logo_rotate);
+       return logo->height;
+}
+
+
+#ifdef CONFIG_FB_LOGO_EXTRA
+
+#define FB_LOGO_EX_NUM_MAX 10
+static struct logo_data_extra {
+       const struct linux_logo *logo;
+       unsigned int n;
+} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
+static unsigned int fb_logo_ex_num;
+
+void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
+{
+       if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
+               return;
+
+       fb_logo_ex[fb_logo_ex_num].logo = logo;
+       fb_logo_ex[fb_logo_ex_num].n = n;
+       fb_logo_ex_num++;
+}
+
+static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
+                                 unsigned int yres)
+{
+       unsigned int i;
+
+       /* FIXME: logo_ex supports only truecolor fb. */
+       if (info->fix.visual != FB_VISUAL_TRUECOLOR)
+               fb_logo_ex_num = 0;
+
+       for (i = 0; i < fb_logo_ex_num; i++) {
+               if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
+                       fb_logo_ex[i].logo = NULL;
+                       continue;
+               }
+               height += fb_logo_ex[i].logo->height;
+               if (height > yres) {
+                       height -= fb_logo_ex[i].logo->height;
+                       fb_logo_ex_num = i;
+                       break;
+               }
+       }
+       return height;
+}
+
+static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+       unsigned int i;
+
+       for (i = 0; i < fb_logo_ex_num; i++)
+               y += fb_show_logo_line(info, rotate,
+                                      fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
+
+       return y;
+}
+
+#else /* !CONFIG_FB_LOGO_EXTRA */
+
+static inline int fb_prepare_extra_logos(struct fb_info *info,
+                                        unsigned int height,
+                                        unsigned int yres)
+{
+       return height;
+}
+
+static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+       return y;
+}
+
+#endif /* CONFIG_FB_LOGO_EXTRA */
+
+
+int fb_prepare_logo(struct fb_info *info, int rotate)
+{
+       int depth = fb_get_color_depth(&info->var, &info->fix);
+       unsigned int yres;
+
+       memset(&fb_logo, 0, sizeof(struct logo_data));
+
+       if (info->flags & FBINFO_MISC_TILEBLITTING ||
+           info->flags & FBINFO_MODULE)
+               return 0;
+
+       if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+               depth = info->var.blue.length;
+               if (info->var.red.length < depth)
+                       depth = info->var.red.length;
+               if (info->var.green.length < depth)
+                       depth = info->var.green.length;
+       }
+
+       if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
+               /* assume console colormap */
+               depth = 4;
+       }
+
+       /* Return if no suitable logo was found */
+       fb_logo.logo = fb_find_logo(depth);
+
+       if (!fb_logo.logo) {
+               return 0;
+       }
+
+       if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
+               yres = info->var.yres;
+       else
+               yres = info->var.xres;
+
+       if (fb_logo.logo->height > yres) {
+               fb_logo.logo = NULL;
+               return 0;
+       }
+
+       /* What depth we asked for might be different from what we get */
+       if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
+               fb_logo.depth = 8;
+       else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
+               fb_logo.depth = 4;
+       else
+               fb_logo.depth = 1;
+
+
+       if (fb_logo.depth > 4 && depth > 4) {
+               switch (info->fix.visual) {
+               case FB_VISUAL_TRUECOLOR:
+                       fb_logo.needs_truepalette = 1;
+                       break;
+               case FB_VISUAL_DIRECTCOLOR:
+                       fb_logo.needs_directpalette = 1;
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               case FB_VISUAL_PSEUDOCOLOR:
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               }
+       }
+
+       return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
+}
+
+int fb_show_logo(struct fb_info *info, int rotate)
+{
+       int y;
+
+       y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
+                             num_online_cpus());
+       y = fb_show_extra_logos(info, y, rotate);
+
+       return y;
+}
+#else
+int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
+int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
+#endif /* CONFIG_LOGO */
+EXPORT_SYMBOL(fb_show_logo);
+
+static void *fb_seq_start(struct seq_file *m, loff_t *pos)
+{
+       mutex_lock(&registration_lock);
+       return (*pos < FB_MAX) ? pos : NULL;
+}
+
+static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (*pos < FB_MAX) ? pos : NULL;
+}
+
+static void fb_seq_stop(struct seq_file *m, void *v)
+{
+       mutex_unlock(&registration_lock);
+}
+
+static int fb_seq_show(struct seq_file *m, void *v)
+{
+       int i = *(loff_t *)v;
+       struct fb_info *fi = registered_fb[i];
+
+       if (fi)
+               seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
+       return 0;
+}
+
+static const struct seq_operations proc_fb_seq_ops = {
+       .start  = fb_seq_start,
+       .next   = fb_seq_next,
+       .stop   = fb_seq_stop,
+       .show   = fb_seq_show,
+};
+
+static int proc_fb_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &proc_fb_seq_ops);
+}
+
+static const struct file_operations fb_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = proc_fb_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/*
+ * We hold a reference to the fb_info in file->private_data,
+ * but if the current registered fb has changed, we don't
+ * actually want to use it.
+ *
+ * So look up the fb_info using the inode minor number,
+ * and just verify it against the reference we have.
+ */
+static struct fb_info *file_fb_info(struct file *file)
+{
+       struct inode *inode = file_inode(file);
+       int fbidx = iminor(inode);
+       struct fb_info *info = registered_fb[fbidx];
+
+       if (info != file->private_data)
+               info = NULL;
+       return info;
+}
+
+static ssize_t
+fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       struct fb_info *info = file_fb_info(file);
+       u8 *buffer, *dst;
+       u8 __iomem *src;
+       int c, cnt = 0, err = 0;
+       unsigned long total_size;
+
+       if (!info || ! info->screen_base)
+               return -ENODEV;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       if (info->fbops->fb_read)
+               return info->fbops->fb_read(info, buf, count, ppos);
+       
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p >= total_size)
+               return 0;
+
+       if (count >= total_size)
+               count = total_size;
+
+       if (count + p > total_size)
+               count = total_size - p;
+
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
+                        GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       src = (u8 __iomem *) (info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       while (count) {
+               c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+               dst = buffer;
+               fb_memcpy_fromfb(dst, src, c);
+               dst += c;
+               src += c;
+
+               if (copy_to_user(buf, buffer, c)) {
+                       err = -EFAULT;
+                       break;
+               }
+               *ppos += c;
+               buf += c;
+               cnt += c;
+               count -= c;
+       }
+
+       kfree(buffer);
+
+       return (err) ? err : cnt;
+}
+
+static ssize_t
+fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       struct fb_info *info = file_fb_info(file);
+       u8 *buffer, *src;
+       u8 __iomem *dst;
+       int c, cnt = 0, err = 0;
+       unsigned long total_size;
+
+       if (!info || !info->screen_base)
+               return -ENODEV;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       if (info->fbops->fb_write)
+               return info->fbops->fb_write(info, buf, count, ppos);
+       
+       total_size = info->screen_size;
+
+       if (total_size == 0)
+               total_size = info->fix.smem_len;
+
+       if (p > total_size)
+               return -EFBIG;
+
+       if (count > total_size) {
+               err = -EFBIG;
+               count = total_size;
+       }
+
+       if (count + p > total_size) {
+               if (!err)
+                       err = -ENOSPC;
+
+               count = total_size - p;
+       }
+
+       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
+                        GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       dst = (u8 __iomem *) (info->screen_base + p);
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       while (count) {
+               c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+               src = buffer;
+
+               if (copy_from_user(src, buf, c)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               fb_memcpy_tofb(dst, src, c);
+               dst += c;
+               src += c;
+               *ppos += c;
+               buf += c;
+               cnt += c;
+               count -= c;
+       }
+
+       kfree(buffer);
+
+       return (cnt) ? cnt : err;
+}
+
+int
+fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       struct fb_fix_screeninfo *fix = &info->fix;
+       unsigned int yres = info->var.yres;
+       int err = 0;
+
+       if (var->yoffset > 0) {
+               if (var->vmode & FB_VMODE_YWRAP) {
+                       if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
+                               err = -EINVAL;
+                       else
+                               yres = 0;
+               } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
+                       err = -EINVAL;
+       }
+
+       if (var->xoffset > 0 && (!fix->xpanstep ||
+                                (var->xoffset % fix->xpanstep)))
+               err = -EINVAL;
+
+       if (err || !info->fbops->fb_pan_display ||
+           var->yoffset > info->var.yres_virtual - yres ||
+           var->xoffset > info->var.xres_virtual - info->var.xres)
+               return -EINVAL;
+
+       if ((err = info->fbops->fb_pan_display(var, info)))
+               return err;
+       info->var.xoffset = var->xoffset;
+       info->var.yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               info->var.vmode |= FB_VMODE_YWRAP;
+       else
+               info->var.vmode &= ~FB_VMODE_YWRAP;
+       return 0;
+}
+EXPORT_SYMBOL(fb_pan_display);
+
+static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
+                        u32 activate)
+{
+       struct fb_event event;
+       struct fb_blit_caps caps, fbcaps;
+       int err = 0;
+
+       memset(&caps, 0, sizeof(caps));
+       memset(&fbcaps, 0, sizeof(fbcaps));
+       caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
+       event.info = info;
+       event.data = &caps;
+       fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
+       info->fbops->fb_get_caps(info, &fbcaps, var);
+
+       if (((fbcaps.x ^ caps.x) & caps.x) ||
+           ((fbcaps.y ^ caps.y) & caps.y) ||
+           (fbcaps.len < caps.len))
+               err = -EINVAL;
+
+       return err;
+}
+
+int
+fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       int flags = info->flags;
+       int ret = 0;
+
+       if (var->activate & FB_ACTIVATE_INV_MODE) {
+               struct fb_videomode mode1, mode2;
+
+               fb_var_to_videomode(&mode1, var);
+               fb_var_to_videomode(&mode2, &info->var);
+               /* make sure we don't delete the videomode of current var */
+               ret = fb_mode_is_equal(&mode1, &mode2);
+
+               if (!ret) {
+                   struct fb_event event;
+
+                   event.info = info;
+                   event.data = &mode1;
+                   ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
+               }
+
+               if (!ret)
+                   fb_delete_videomode(&mode1, &info->modelist);
+
+
+               ret = (ret) ? -EINVAL : 0;
+               goto done;
+       }
+
+       if ((var->activate & FB_ACTIVATE_FORCE) ||
+           memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
+               u32 activate = var->activate;
+
+               /* When using FOURCC mode, make sure the red, green, blue and
+                * transp fields are set to 0.
+                */
+               if ((info->fix.capabilities & FB_CAP_FOURCC) &&
+                   var->grayscale > 1) {
+                       if (var->red.offset     || var->green.offset    ||
+                           var->blue.offset    || var->transp.offset   ||
+                           var->red.length     || var->green.length    ||
+                           var->blue.length    || var->transp.length   ||
+                           var->red.msb_right  || var->green.msb_right ||
+                           var->blue.msb_right || var->transp.msb_right)
+                               return -EINVAL;
+               }
+
+               if (!info->fbops->fb_check_var) {
+                       *var = info->var;
+                       goto done;
+               }
+
+               ret = info->fbops->fb_check_var(var, info);
+
+               if (ret)
+                       goto done;
+
+               if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+                       struct fb_var_screeninfo old_var;
+                       struct fb_videomode mode;
+
+                       if (info->fbops->fb_get_caps) {
+                               ret = fb_check_caps(info, var, activate);
+
+                               if (ret)
+                                       goto done;
+                       }
+
+                       old_var = info->var;
+                       info->var = *var;
+
+                       if (info->fbops->fb_set_par) {
+                               ret = info->fbops->fb_set_par(info);
+
+                               if (ret) {
+                                       info->var = old_var;
+                                       printk(KERN_WARNING "detected "
+                                               "fb_set_par error, "
+                                               "error code: %d\n", ret);
+                                       goto done;
+                               }
+                       }
+
+                       fb_pan_display(info, &info->var);
+                       fb_set_cmap(&info->cmap, info);
+                       fb_var_to_videomode(&mode, &info->var);
+
+                       if (info->modelist.prev && info->modelist.next &&
+                           !list_empty(&info->modelist))
+                               ret = fb_add_videomode(&mode, &info->modelist);
+
+                       if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
+                               struct fb_event event;
+                               int evnt = (activate & FB_ACTIVATE_ALL) ?
+                                       FB_EVENT_MODE_CHANGE_ALL :
+                                       FB_EVENT_MODE_CHANGE;
+
+                               info->flags &= ~FBINFO_MISC_USEREVENT;
+                               event.info = info;
+                               event.data = &mode;
+                               fb_notifier_call_chain(evnt, &event);
+                       }
+               }
+       }
+
+ done:
+       return ret;
+}
+EXPORT_SYMBOL(fb_set_var);
+
+int
+fb_blank(struct fb_info *info, int blank)
+{      
+       struct fb_event event;
+       int ret = -EINVAL, early_ret;
+
+       if (blank > FB_BLANK_POWERDOWN)
+               blank = FB_BLANK_POWERDOWN;
+
+       event.info = info;
+       event.data = &blank;
+
+       early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
+
+       if (info->fbops->fb_blank)
+               ret = info->fbops->fb_blank(blank, info);
+
+       if (!ret)
+               fb_notifier_call_chain(FB_EVENT_BLANK, &event);
+       else {
+               /*
+                * if fb_blank is failed then revert effects of
+                * the early blank event.
+                */
+               if (!early_ret)
+                       fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(fb_blank);
+
+static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct fb_ops *fb;
+       struct fb_var_screeninfo var;
+       struct fb_fix_screeninfo fix;
+       struct fb_con2fbmap con2fb;
+       struct fb_cmap cmap_from;
+       struct fb_cmap_user cmap;
+       struct fb_event event;
+       void __user *argp = (void __user *)arg;
+       long ret = 0;
+
+       switch (cmd) {
+       case FBIOGET_VSCREENINFO:
+               if (!lock_fb_info(info))
+                       return -ENODEV;
+               var = info->var;
+               unlock_fb_info(info);
+
+               ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
+               break;
+       case FBIOPUT_VSCREENINFO:
+               if (copy_from_user(&var, argp, sizeof(var)))
+                       return -EFAULT;
+               console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
+               info->flags |= FBINFO_MISC_USEREVENT;
+               ret = fb_set_var(info, &var);
+               info->flags &= ~FBINFO_MISC_USEREVENT;
+               unlock_fb_info(info);
+               console_unlock();
+               if (!ret && copy_to_user(argp, &var, sizeof(var)))
+                       ret = -EFAULT;
+               break;
+       case FBIOGET_FSCREENINFO:
+               if (!lock_fb_info(info))
+                       return -ENODEV;
+               fix = info->fix;
+               unlock_fb_info(info);
+
+               ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
+               break;
+       case FBIOPUTCMAP:
+               if (copy_from_user(&cmap, argp, sizeof(cmap)))
+                       return -EFAULT;
+               ret = fb_set_user_cmap(&cmap, info);
+               break;
+       case FBIOGETCMAP:
+               if (copy_from_user(&cmap, argp, sizeof(cmap)))
+                       return -EFAULT;
+               if (!lock_fb_info(info))
+                       return -ENODEV;
+               cmap_from = info->cmap;
+               unlock_fb_info(info);
+               ret = fb_cmap_to_user(&cmap_from, &cmap);
+               break;
+       case FBIOPAN_DISPLAY:
+               if (copy_from_user(&var, argp, sizeof(var)))
+                       return -EFAULT;
+               console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
+               ret = fb_pan_display(info, &var);
+               unlock_fb_info(info);
+               console_unlock();
+               if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
+                       return -EFAULT;
+               break;
+       case FBIO_CURSOR:
+               ret = -EINVAL;
+               break;
+       case FBIOGET_CON2FBMAP:
+               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+                       return -EFAULT;
+               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+                       return -EINVAL;
+               con2fb.framebuffer = -1;
+               event.data = &con2fb;
+               if (!lock_fb_info(info))
+                       return -ENODEV;
+               event.info = info;
+               fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
+               unlock_fb_info(info);
+               ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
+               break;
+       case FBIOPUT_CON2FBMAP:
+               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+                       return -EFAULT;
+               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+                       return -EINVAL;
+               if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
+                       return -EINVAL;
+               if (!registered_fb[con2fb.framebuffer])
+                       request_module("fb%d", con2fb.framebuffer);
+               if (!registered_fb[con2fb.framebuffer]) {
+                       ret = -EINVAL;
+                       break;
+               }
+               event.data = &con2fb;
+               console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
+               event.info = info;
+               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
+               unlock_fb_info(info);
+               console_unlock();
+               break;
+       case FBIOBLANK:
+               console_lock();
+               if (!lock_fb_info(info)) {
+                       console_unlock();
+                       return -ENODEV;
+               }
+               info->flags |= FBINFO_MISC_USEREVENT;
+               ret = fb_blank(info, arg);
+               info->flags &= ~FBINFO_MISC_USEREVENT;
+               unlock_fb_info(info);
+               console_unlock();
+               break;
+       default:
+               if (!lock_fb_info(info))
+                       return -ENODEV;
+               fb = info->fbops;
+               if (fb->fb_ioctl)
+                       ret = fb->fb_ioctl(info, cmd, arg);
+               else
+                       ret = -ENOTTY;
+               unlock_fb_info(info);
+       }
+       return ret;
+}
+
+static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct fb_info *info = file_fb_info(file);
+
+       if (!info)
+               return -ENODEV;
+       return do_fb_ioctl(info, cmd, arg);
+}
+
+#ifdef CONFIG_COMPAT
+struct fb_fix_screeninfo32 {
+       char                    id[16];
+       compat_caddr_t          smem_start;
+       u32                     smem_len;
+       u32                     type;
+       u32                     type_aux;
+       u32                     visual;
+       u16                     xpanstep;
+       u16                     ypanstep;
+       u16                     ywrapstep;
+       u32                     line_length;
+       compat_caddr_t          mmio_start;
+       u32                     mmio_len;
+       u32                     accel;
+       u16                     reserved[3];
+};
+
+struct fb_cmap32 {
+       u32                     start;
+       u32                     len;
+       compat_caddr_t  red;
+       compat_caddr_t  green;
+       compat_caddr_t  blue;
+       compat_caddr_t  transp;
+};
+
+static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
+                         unsigned long arg)
+{
+       struct fb_cmap_user __user *cmap;
+       struct fb_cmap32 __user *cmap32;
+       __u32 data;
+       int err;
+
+       cmap = compat_alloc_user_space(sizeof(*cmap));
+       cmap32 = compat_ptr(arg);
+
+       if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
+               return -EFAULT;
+
+       if (get_user(data, &cmap32->red) ||
+           put_user(compat_ptr(data), &cmap->red) ||
+           get_user(data, &cmap32->green) ||
+           put_user(compat_ptr(data), &cmap->green) ||
+           get_user(data, &cmap32->blue) ||
+           put_user(compat_ptr(data), &cmap->blue) ||
+           get_user(data, &cmap32->transp) ||
+           put_user(compat_ptr(data), &cmap->transp))
+               return -EFAULT;
+
+       err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
+
+       if (!err) {
+               if (copy_in_user(&cmap32->start,
+                                &cmap->start,
+                                2 * sizeof(__u32)))
+                       err = -EFAULT;
+       }
+       return err;
+}
+
+static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
+                                 struct fb_fix_screeninfo32 __user *fix32)
+{
+       __u32 data;
+       int err;
+
+       err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
+
+       data = (__u32) (unsigned long) fix->smem_start;
+       err |= put_user(data, &fix32->smem_start);
+
+       err |= put_user(fix->smem_len, &fix32->smem_len);
+       err |= put_user(fix->type, &fix32->type);
+       err |= put_user(fix->type_aux, &fix32->type_aux);
+       err |= put_user(fix->visual, &fix32->visual);
+       err |= put_user(fix->xpanstep, &fix32->xpanstep);
+       err |= put_user(fix->ypanstep, &fix32->ypanstep);
+       err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
+       err |= put_user(fix->line_length, &fix32->line_length);
+
+       data = (__u32) (unsigned long) fix->mmio_start;
+       err |= put_user(data, &fix32->mmio_start);
+
+       err |= put_user(fix->mmio_len, &fix32->mmio_len);
+       err |= put_user(fix->accel, &fix32->accel);
+       err |= copy_to_user(fix32->reserved, fix->reserved,
+                           sizeof(fix->reserved));
+
+       if (err)
+               return -EFAULT;
+       return 0;
+}
+
+static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
+                             unsigned long arg)
+{
+       mm_segment_t old_fs;
+       struct fb_fix_screeninfo fix;
+       struct fb_fix_screeninfo32 __user *fix32;
+       int err;
+
+       fix32 = compat_ptr(arg);
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
+       set_fs(old_fs);
+
+       if (!err)
+               err = do_fscreeninfo_to_user(&fix, fix32);
+
+       return err;
+}
+
+static long fb_compat_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct fb_info *info = file_fb_info(file);
+       struct fb_ops *fb;
+       long ret = -ENOIOCTLCMD;
+
+       if (!info)
+               return -ENODEV;
+       fb = info->fbops;
+       switch(cmd) {
+       case FBIOGET_VSCREENINFO:
+       case FBIOPUT_VSCREENINFO:
+       case FBIOPAN_DISPLAY:
+       case FBIOGET_CON2FBMAP:
+       case FBIOPUT_CON2FBMAP:
+               arg = (unsigned long) compat_ptr(arg);
+       case FBIOBLANK:
+               ret = do_fb_ioctl(info, cmd, arg);
+               break;
+
+       case FBIOGET_FSCREENINFO:
+               ret = fb_get_fscreeninfo(info, cmd, arg);
+               break;
+
+       case FBIOGETCMAP:
+       case FBIOPUTCMAP:
+               ret = fb_getput_cmap(info, cmd, arg);
+               break;
+
+       default:
+               if (fb->fb_compat_ioctl)
+                       ret = fb->fb_compat_ioctl(info, cmd, arg);
+               break;
+       }
+       return ret;
+}
+#endif
+
+static int
+fb_mmap(struct file *file, struct vm_area_struct * vma)
+{
+       struct fb_info *info = file_fb_info(file);
+       struct fb_ops *fb;
+       unsigned long mmio_pgoff;
+       unsigned long start;
+       u32 len;
+
+       if (!info)
+               return -ENODEV;
+       fb = info->fbops;
+       if (!fb)
+               return -ENODEV;
+       mutex_lock(&info->mm_lock);
+       if (fb->fb_mmap) {
+               int res;
+               res = fb->fb_mmap(info, vma);
+               mutex_unlock(&info->mm_lock);
+               return res;
+       }
+
+       /*
+        * Ugh. This can be either the frame buffer mapping, or
+        * if pgoff points past it, the mmio mapping.
+        */
+       start = info->fix.smem_start;
+       len = info->fix.smem_len;
+       mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
+       if (vma->vm_pgoff >= mmio_pgoff) {
+               if (info->var.accel_flags) {
+                       mutex_unlock(&info->mm_lock);
+                       return -EINVAL;
+               }
+
+               vma->vm_pgoff -= mmio_pgoff;
+               start = info->fix.mmio_start;
+               len = info->fix.mmio_len;
+       }
+       mutex_unlock(&info->mm_lock);
+
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       fb_pgprotect(file, vma, start);
+
+       return vm_iomap_memory(vma, start, len);
+}
+
+static int
+fb_open(struct inode *inode, struct file *file)
+__acquires(&info->lock)
+__releases(&info->lock)
+{
+       int fbidx = iminor(inode);
+       struct fb_info *info;
+       int res = 0;
+
+       info = get_fb_info(fbidx);
+       if (!info) {
+               request_module("fb%d", fbidx);
+               info = get_fb_info(fbidx);
+               if (!info)
+                       return -ENODEV;
+       }
+       if (IS_ERR(info))
+               return PTR_ERR(info);
+
+       mutex_lock(&info->lock);
+       if (!try_module_get(info->fbops->owner)) {
+               res = -ENODEV;
+               goto out;
+       }
+       file->private_data = info;
+       if (info->fbops->fb_open) {
+               res = info->fbops->fb_open(info,1);
+               if (res)
+                       module_put(info->fbops->owner);
+       }
+#ifdef CONFIG_FB_DEFERRED_IO
+       if (info->fbdefio)
+               fb_deferred_io_open(info, inode, file);
+#endif
+out:
+       mutex_unlock(&info->lock);
+       if (res)
+               put_fb_info(info);
+       return res;
+}
+
+static int 
+fb_release(struct inode *inode, struct file *file)
+__acquires(&info->lock)
+__releases(&info->lock)
+{
+       struct fb_info * const info = file->private_data;
+
+       mutex_lock(&info->lock);
+       if (info->fbops->fb_release)
+               info->fbops->fb_release(info,1);
+       module_put(info->fbops->owner);
+       mutex_unlock(&info->lock);
+       put_fb_info(info);
+       return 0;
+}
+
+static const struct file_operations fb_fops = {
+       .owner =        THIS_MODULE,
+       .read =         fb_read,
+       .write =        fb_write,
+       .unlocked_ioctl = fb_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = fb_compat_ioctl,
+#endif
+       .mmap =         fb_mmap,
+       .open =         fb_open,
+       .release =      fb_release,
+#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
+       .get_unmapped_area = get_fb_unmapped_area,
+#endif
+#ifdef CONFIG_FB_DEFERRED_IO
+       .fsync =        fb_deferred_io_fsync,
+#endif
+       .llseek =       default_llseek,
+};
+
+struct class *fb_class;
+EXPORT_SYMBOL(fb_class);
+
+static int fb_check_foreignness(struct fb_info *fi)
+{
+       const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
+
+       fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
+
+#ifdef __BIG_ENDIAN
+       fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
+#else
+       fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
+#endif /* __BIG_ENDIAN */
+
+       if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
+               pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
+                      "support this framebuffer\n", fi->fix.id);
+               return -ENOSYS;
+       } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
+               pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
+                      "support this framebuffer\n", fi->fix.id);
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
+static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
+{
+       /* is the generic aperture base the same as the HW one */
+       if (gen->base == hw->base)
+               return true;
+       /* is the generic aperture base inside the hw base->hw base+size */
+       if (gen->base > hw->base && gen->base < hw->base + hw->size)
+               return true;
+       return false;
+}
+
+static bool fb_do_apertures_overlap(struct apertures_struct *gena,
+                                   struct apertures_struct *hwa)
+{
+       int i, j;
+       if (!hwa || !gena)
+               return false;
+
+       for (i = 0; i < hwa->count; ++i) {
+               struct aperture *h = &hwa->ranges[i];
+               for (j = 0; j < gena->count; ++j) {
+                       struct aperture *g = &gena->ranges[j];
+                       printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
+                               (unsigned long long)g->base,
+                               (unsigned long long)g->size,
+                               (unsigned long long)h->base,
+                               (unsigned long long)h->size);
+                       if (apertures_overlap(g, h))
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+static int do_unregister_framebuffer(struct fb_info *fb_info);
+
+#define VGA_FB_PHYS 0xA0000
+static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
+                                             const char *name, bool primary)
+{
+       int i, ret;
+
+       /* check all firmware fbs and kick off if the base addr overlaps */
+       for (i = 0 ; i < FB_MAX; i++) {
+               struct apertures_struct *gen_aper;
+               if (!registered_fb[i])
+                       continue;
+
+               if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
+                       continue;
+
+               gen_aper = registered_fb[i]->apertures;
+               if (fb_do_apertures_overlap(gen_aper, a) ||
+                       (primary && gen_aper && gen_aper->count &&
+                        gen_aper->ranges[0].base == VGA_FB_PHYS)) {
+
+                       printk(KERN_INFO "fb: switching to %s from %s\n",
+                              name, registered_fb[i]->fix.id);
+                       ret = do_unregister_framebuffer(registered_fb[i]);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int do_register_framebuffer(struct fb_info *fb_info)
+{
+       int i, ret;
+       struct fb_event event;
+       struct fb_videomode mode;
+
+       if (fb_check_foreignness(fb_info))
+               return -ENOSYS;
+
+       ret = do_remove_conflicting_framebuffers(fb_info->apertures,
+                                                fb_info->fix.id,
+                                                fb_is_primary_device(fb_info));
+       if (ret)
+               return ret;
+
+       if (num_registered_fb == FB_MAX)
+               return -ENXIO;
+
+       num_registered_fb++;
+       for (i = 0 ; i < FB_MAX; i++)
+               if (!registered_fb[i])
+                       break;
+       fb_info->node = i;
+       atomic_set(&fb_info->count, 1);
+       mutex_init(&fb_info->lock);
+       mutex_init(&fb_info->mm_lock);
+
+       fb_info->dev = device_create(fb_class, fb_info->device,
+                                    MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
+       if (IS_ERR(fb_info->dev)) {
+               /* Not fatal */
+               printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
+               fb_info->dev = NULL;
+       } else
+               fb_init_device(fb_info);
+
+       if (fb_info->pixmap.addr == NULL) {
+               fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
+               if (fb_info->pixmap.addr) {
+                       fb_info->pixmap.size = FBPIXMAPSIZE;
+                       fb_info->pixmap.buf_align = 1;
+                       fb_info->pixmap.scan_align = 1;
+                       fb_info->pixmap.access_align = 32;
+                       fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
+               }
+       }       
+       fb_info->pixmap.offset = 0;
+
+       if (!fb_info->pixmap.blit_x)
+               fb_info->pixmap.blit_x = ~(u32)0;
+
+       if (!fb_info->pixmap.blit_y)
+               fb_info->pixmap.blit_y = ~(u32)0;
+
+       if (!fb_info->modelist.prev || !fb_info->modelist.next)
+               INIT_LIST_HEAD(&fb_info->modelist);
+
+       if (fb_info->skip_vt_switch)
+               pm_vt_switch_required(fb_info->dev, false);
+       else
+               pm_vt_switch_required(fb_info->dev, true);
+
+       fb_var_to_videomode(&mode, &fb_info->var);
+       fb_add_videomode(&mode, &fb_info->modelist);
+       registered_fb[i] = fb_info;
+
+       event.info = fb_info;
+       console_lock();
+       if (!lock_fb_info(fb_info)) {
+               console_unlock();
+               return -ENODEV;
+       }
+
+       fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
+       unlock_fb_info(fb_info);
+       console_unlock();
+       return 0;
+}
+
+static int do_unregister_framebuffer(struct fb_info *fb_info)
+{
+       struct fb_event event;
+       int i, ret = 0;
+
+       i = fb_info->node;
+       if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
+               return -EINVAL;
+
+       console_lock();
+       if (!lock_fb_info(fb_info)) {
+               console_unlock();
+               return -ENODEV;
+       }
+
+       event.info = fb_info;
+       ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
+       unlock_fb_info(fb_info);
+       console_unlock();
+
+       if (ret)
+               return -EINVAL;
+
+       pm_vt_switch_unregister(fb_info->dev);
+
+       unlink_framebuffer(fb_info);
+       if (fb_info->pixmap.addr &&
+           (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+               kfree(fb_info->pixmap.addr);
+       fb_destroy_modelist(&fb_info->modelist);
+       registered_fb[i] = NULL;
+       num_registered_fb--;
+       fb_cleanup_device(fb_info);
+       event.info = fb_info;
+       console_lock();
+       fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
+       console_unlock();
+
+       /* this may free fb info */
+       put_fb_info(fb_info);
+       return 0;
+}
+
+int unlink_framebuffer(struct fb_info *fb_info)
+{
+       int i;
+
+       i = fb_info->node;
+       if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
+               return -EINVAL;
+
+       if (fb_info->dev) {
+               device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+               fb_info->dev = NULL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(unlink_framebuffer);
+
+int remove_conflicting_framebuffers(struct apertures_struct *a,
+                                   const char *name, bool primary)
+{
+       int ret;
+
+       mutex_lock(&registration_lock);
+       ret = do_remove_conflicting_framebuffers(a, name, primary);
+       mutex_unlock(&registration_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(remove_conflicting_framebuffers);
+
+/**
+ *     register_framebuffer - registers a frame buffer device
+ *     @fb_info: frame buffer info structure
+ *
+ *     Registers a frame buffer device @fb_info.
+ *
+ *     Returns negative errno on error, or zero for success.
+ *
+ */
+int
+register_framebuffer(struct fb_info *fb_info)
+{
+       int ret;
+
+       mutex_lock(&registration_lock);
+       ret = do_register_framebuffer(fb_info);
+       mutex_unlock(&registration_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(register_framebuffer);
+
+/**
+ *     unregister_framebuffer - releases a frame buffer device
+ *     @fb_info: frame buffer info structure
+ *
+ *     Unregisters a frame buffer device @fb_info.
+ *
+ *     Returns negative errno on error, or zero for success.
+ *
+ *      This function will also notify the framebuffer console
+ *      to release the driver.
+ *
+ *      This is meant to be called within a driver's module_exit()
+ *      function. If this is called outside module_exit(), ensure
+ *      that the driver implements fb_open() and fb_release() to
+ *      check that no processes are using the device.
+ */
+int
+unregister_framebuffer(struct fb_info *fb_info)
+{
+       int ret;
+
+       mutex_lock(&registration_lock);
+       ret = do_unregister_framebuffer(fb_info);
+       mutex_unlock(&registration_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(unregister_framebuffer);
+
+/**
+ *     fb_set_suspend - low level driver signals suspend
+ *     @info: framebuffer affected
+ *     @state: 0 = resuming, !=0 = suspending
+ *
+ *     This is meant to be used by low level drivers to
+ *     signal suspend/resume to the core & clients.
+ *     It must be called with the console semaphore held
+ */
+void fb_set_suspend(struct fb_info *info, int state)
+{
+       struct fb_event event;
+
+       event.info = info;
+       if (state) {
+               fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
+               info->state = FBINFO_STATE_SUSPENDED;
+       } else {
+               info->state = FBINFO_STATE_RUNNING;
+               fb_notifier_call_chain(FB_EVENT_RESUME, &event);
+       }
+}
+EXPORT_SYMBOL(fb_set_suspend);
+
+/**
+ *     fbmem_init - init frame buffer subsystem
+ *
+ *     Initialize the frame buffer subsystem.
+ *
+ *     NOTE: This function is _only_ to be called by drivers/char/mem.c.
+ *
+ */
+
+static int __init
+fbmem_init(void)
+{
+       proc_create("fb", 0, NULL, &fb_proc_fops);
+
+       if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
+               printk("unable to get major %d for fb devs\n", FB_MAJOR);
+
+       fb_class = class_create(THIS_MODULE, "graphics");
+       if (IS_ERR(fb_class)) {
+               printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
+               fb_class = NULL;
+       }
+       return 0;
+}
+
+#ifdef MODULE
+module_init(fbmem_init);
+static void __exit
+fbmem_exit(void)
+{
+       remove_proc_entry("fb", NULL);
+       class_destroy(fb_class);
+       unregister_chrdev(FB_MAJOR, "fb");
+}
+
+module_exit(fbmem_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Framebuffer base");
+#else
+subsys_initcall(fbmem_init);
+#endif
+
+int fb_new_modelist(struct fb_info *info)
+{
+       struct fb_event event;
+       struct fb_var_screeninfo var = info->var;
+       struct list_head *pos, *n;
+       struct fb_modelist *modelist;
+       struct fb_videomode *m, mode;
+       int err = 1;
+
+       list_for_each_safe(pos, n, &info->modelist) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+               fb_videomode_to_var(&var, m);
+               var.activate = FB_ACTIVATE_TEST;
+               err = fb_set_var(info, &var);
+               fb_var_to_videomode(&mode, &var);
+               if (err || !fb_mode_is_equal(m, &mode)) {
+                       list_del(pos);
+                       kfree(pos);
+               }
+       }
+
+       err = 1;
+
+       if (!list_empty(&info->modelist)) {
+               event.info = info;
+               err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
+       }
+
+       return err;
+}
+
+static char *video_options[FB_MAX] __read_mostly;
+static int ofonly __read_mostly;
+
+/**
+ * fb_get_options - get kernel boot parameters
+ * @name:   framebuffer name as it would appear in
+ *          the boot parameter line
+ *          (video=<name>:<options>)
+ * @option: the option will be stored here
+ *
+ * NOTE: Needed to maintain backwards compatibility
+ */
+int fb_get_options(const char *name, char **option)
+{
+       char *opt, *options = NULL;
+       int retval = 0;
+       int name_len = strlen(name), i;
+
+       if (name_len && ofonly && strncmp(name, "offb", 4))
+               retval = 1;
+
+       if (name_len && !retval) {
+               for (i = 0; i < FB_MAX; i++) {
+                       if (video_options[i] == NULL)
+                               continue;
+                       if (!video_options[i][0])
+                               continue;
+                       opt = video_options[i];
+                       if (!strncmp(name, opt, name_len) &&
+                           opt[name_len] == ':')
+                               options = opt + name_len + 1;
+               }
+       }
+       /* No match, pass global option */
+       if (!options && option && fb_mode_option)
+               options = kstrdup(fb_mode_option, GFP_KERNEL);
+       if (options && !strncmp(options, "off", 3))
+               retval = 1;
+
+       if (option)
+               *option = options;
+
+       return retval;
+}
+EXPORT_SYMBOL(fb_get_options);
+
+#ifndef MODULE
+/**
+ *     video_setup - process command line options
+ *     @options: string of options
+ *
+ *     Process command line options for frame buffer subsystem.
+ *
+ *     NOTE: This function is a __setup and __init function.
+ *            It only stores the options.  Drivers have to call
+ *            fb_get_options() as necessary.
+ *
+ *     Returns zero.
+ *
+ */
+static int __init video_setup(char *options)
+{
+       int i, global = 0;
+
+       if (!options || !*options)
+               global = 1;
+
+       if (!global && !strncmp(options, "ofonly", 6)) {
+               ofonly = 1;
+               global = 1;
+       }
+
+       if (!global && !strchr(options, ':')) {
+               fb_mode_option = options;
+               global = 1;
+       }
+
+       if (!global) {
+               for (i = 0; i < FB_MAX; i++) {
+                       if (video_options[i] == NULL) {
+                               video_options[i] = options;
+                               break;
+                       }
+
+               }
+       }
+
+       return 1;
+}
+__setup("video=", video_setup);
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
new file mode 100644 (file)
index 0000000..c204ebe
--- /dev/null
@@ -0,0 +1,1592 @@
+/*
+ * linux/drivers/video/fbmon.c
+ *
+ * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
+ *
+ * Credits:
+ *
+ * The EDID Parser is a conglomeration from the following sources:
+ *
+ *   1. SciTech SNAP Graphics Architecture
+ *      Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
+ *
+ *   2. XFree86 4.3.0, interpret_edid.c
+ *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
+ *
+ *   3. John Fremlin <vii@users.sourceforge.net> and
+ *      Ani Joshi <ajoshi@unixbox.com>
+ *
+ * Generalized Timing Formula is derived from:
+ *
+ *      GTF Spreadsheet by Andy Morrish (1/5/97)
+ *      available at http://www.vesa.org
+ *
+ * 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.
+ *
+ */
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <video/edid.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#include "../edid.h"
+
+/*
+ * EDID parser
+ */
+
+#undef DEBUG  /* define this for verbose EDID parsing output */
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define FBMON_FIX_HEADER  1
+#define FBMON_FIX_INPUT   2
+#define FBMON_FIX_TIMINGS 3
+
+#ifdef CONFIG_FB_MODE_HELPERS
+struct broken_edid {
+       u8  manufacturer[4];
+       u32 model;
+       u32 fix;
+};
+
+static const struct broken_edid brokendb[] = {
+       /* DEC FR-PCXAV-YZ */
+       {
+               .manufacturer = "DEC",
+               .model        = 0x073a,
+               .fix          = FBMON_FIX_HEADER,
+       },
+       /* ViewSonic PF775a */
+       {
+               .manufacturer = "VSC",
+               .model        = 0x5a44,
+               .fix          = FBMON_FIX_INPUT,
+       },
+       /* Sharp UXGA? */
+       {
+               .manufacturer = "SHP",
+               .model        = 0x138e,
+               .fix          = FBMON_FIX_TIMINGS,
+       },
+};
+
+static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0x00
+};
+
+static void copy_string(unsigned char *c, unsigned char *s)
+{
+  int i;
+  c = c + 5;
+  for (i = 0; (i < 13 && *c != 0x0A); i++)
+    *(s++) = *(c++);
+  *s = 0;
+  while (i-- && (*--s == 0x20)) *s = 0;
+}
+
+static int edid_is_serial_block(unsigned char *block)
+{
+       if ((block[0] == 0x00) && (block[1] == 0x00) &&
+           (block[2] == 0x00) && (block[3] == 0xff) &&
+           (block[4] == 0x00))
+               return 1;
+       else
+               return 0;
+}
+
+static int edid_is_ascii_block(unsigned char *block)
+{
+       if ((block[0] == 0x00) && (block[1] == 0x00) &&
+           (block[2] == 0x00) && (block[3] == 0xfe) &&
+           (block[4] == 0x00))
+               return 1;
+       else
+               return 0;
+}
+
+static int edid_is_limits_block(unsigned char *block)
+{
+       if ((block[0] == 0x00) && (block[1] == 0x00) &&
+           (block[2] == 0x00) && (block[3] == 0xfd) &&
+           (block[4] == 0x00))
+               return 1;
+       else
+               return 0;
+}
+
+static int edid_is_monitor_block(unsigned char *block)
+{
+       if ((block[0] == 0x00) && (block[1] == 0x00) &&
+           (block[2] == 0x00) && (block[3] == 0xfc) &&
+           (block[4] == 0x00))
+               return 1;
+       else
+               return 0;
+}
+
+static int edid_is_timing_block(unsigned char *block)
+{
+       if ((block[0] != 0x00) || (block[1] != 0x00) ||
+           (block[2] != 0x00) || (block[4] != 0x00))
+               return 1;
+       else
+               return 0;
+}
+
+static int check_edid(unsigned char *edid)
+{
+       unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
+       unsigned char *b;
+       u32 model;
+       int i, fix = 0, ret = 0;
+
+       manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+       manufacturer[1] = ((block[0] & 0x03) << 3) +
+               ((block[1] & 0xe0) >> 5) + '@';
+       manufacturer[2] = (block[1] & 0x1f) + '@';
+       manufacturer[3] = 0;
+       model = block[2] + (block[3] << 8);
+
+       for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
+               if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
+                       brokendb[i].model == model) {
+                       fix = brokendb[i].fix;
+                       break;
+               }
+       }
+
+       switch (fix) {
+       case FBMON_FIX_HEADER:
+               for (i = 0; i < 8; i++) {
+                       if (edid[i] != edid_v1_header[i]) {
+                               ret = fix;
+                               break;
+                       }
+               }
+               break;
+       case FBMON_FIX_INPUT:
+               b = edid + EDID_STRUCT_DISPLAY;
+               /* Only if display is GTF capable will
+                  the input type be reset to analog */
+               if (b[4] & 0x01 && b[0] & 0x80)
+                       ret = fix;
+               break;
+       case FBMON_FIX_TIMINGS:
+               b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+               ret = fix;
+
+               for (i = 0; i < 4; i++) {
+                       if (edid_is_limits_block(b)) {
+                               ret = 0;
+                               break;
+                       }
+
+                       b += DETAILED_TIMING_DESCRIPTION_SIZE;
+               }
+
+               break;
+       }
+
+       if (ret)
+               printk("fbmon: The EDID Block of "
+                      "Manufacturer: %s Model: 0x%x is known to "
+                      "be broken,\n",  manufacturer, model);
+
+       return ret;
+}
+
+static void fix_edid(unsigned char *edid, int fix)
+{
+       int i;
+       unsigned char *b, csum = 0;
+
+       switch (fix) {
+       case FBMON_FIX_HEADER:
+               printk("fbmon: trying a header reconstruct\n");
+               memcpy(edid, edid_v1_header, 8);
+               break;
+       case FBMON_FIX_INPUT:
+               printk("fbmon: trying to fix input type\n");
+               b = edid + EDID_STRUCT_DISPLAY;
+               b[0] &= ~0x80;
+               edid[127] += 0x80;
+               break;
+       case FBMON_FIX_TIMINGS:
+               printk("fbmon: trying to fix monitor timings\n");
+               b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+               for (i = 0; i < 4; i++) {
+                       if (!(edid_is_serial_block(b) ||
+                             edid_is_ascii_block(b) ||
+                             edid_is_monitor_block(b) ||
+                             edid_is_timing_block(b))) {
+                               b[0] = 0x00;
+                               b[1] = 0x00;
+                               b[2] = 0x00;
+                               b[3] = 0xfd;
+                               b[4] = 0x00;
+                               b[5] = 60;   /* vfmin */
+                               b[6] = 60;   /* vfmax */
+                               b[7] = 30;   /* hfmin */
+                               b[8] = 75;   /* hfmax */
+                               b[9] = 17;   /* pixclock - 170 MHz*/
+                               b[10] = 0;   /* GTF */
+                               break;
+                       }
+
+                       b += DETAILED_TIMING_DESCRIPTION_SIZE;
+               }
+
+               for (i = 0; i < EDID_LENGTH - 1; i++)
+                       csum += edid[i];
+
+               edid[127] = 256 - csum;
+               break;
+       }
+}
+
+static int edid_checksum(unsigned char *edid)
+{
+       unsigned char csum = 0, all_null = 0;
+       int i, err = 0, fix = check_edid(edid);
+
+       if (fix)
+               fix_edid(edid, fix);
+
+       for (i = 0; i < EDID_LENGTH; i++) {
+               csum += edid[i];
+               all_null |= edid[i];
+       }
+
+       if (csum == 0x00 && all_null) {
+               /* checksum passed, everything's good */
+               err = 1;
+       }
+
+       return err;
+}
+
+static int edid_check_header(unsigned char *edid)
+{
+       int i, err = 1, fix = check_edid(edid);
+
+       if (fix)
+               fix_edid(edid, fix);
+
+       for (i = 0; i < 8; i++) {
+               if (edid[i] != edid_v1_header[i])
+                       err = 0;
+       }
+
+       return err;
+}
+
+static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
+{
+       specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+       specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
+               ((block[1] & 0xe0) >> 5) + '@';
+       specs->manufacturer[2] = (block[1] & 0x1f) + '@';
+       specs->manufacturer[3] = 0;
+       specs->model = block[2] + (block[3] << 8);
+       specs->serial = block[4] + (block[5] << 8) +
+              (block[6] << 16) + (block[7] << 24);
+       specs->year = block[9] + 1990;
+       specs->week = block[8];
+       DPRINTK("   Manufacturer: %s\n", specs->manufacturer);
+       DPRINTK("   Model: %x\n", specs->model);
+       DPRINTK("   Serial#: %u\n", specs->serial);
+       DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);
+}
+
+static void get_dpms_capabilities(unsigned char flags,
+                                 struct fb_monspecs *specs)
+{
+       specs->dpms = 0;
+       if (flags & DPMS_ACTIVE_OFF)
+               specs->dpms |= FB_DPMS_ACTIVE_OFF;
+       if (flags & DPMS_SUSPEND)
+               specs->dpms |= FB_DPMS_SUSPEND;
+       if (flags & DPMS_STANDBY)
+               specs->dpms |= FB_DPMS_STANDBY;
+       DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
+              (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
+              (flags & DPMS_SUSPEND)    ? "yes" : "no",
+              (flags & DPMS_STANDBY)    ? "yes" : "no");
+}
+
+static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
+{
+       int tmp;
+
+       DPRINTK("      Chroma\n");
+       /* Chromaticity data */
+       tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.redx = tmp/1024;
+       DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);
+
+       tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.redy = tmp/1024;
+       DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);
+
+       tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.greenx = tmp/1024;
+       DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);
+
+       tmp = (block[5] & 3) | (block[0xa] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.greeny = tmp/1024;
+       DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);
+
+       tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.bluex = tmp/1024;
+       DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);
+
+       tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.bluey = tmp/1024;
+       DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
+
+       tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.whitex = tmp/1024;
+       DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);
+
+       tmp = (block[6] & 3) | (block[0xe] << 2);
+       tmp *= 1000;
+       tmp += 512;
+       specs->chroma.whitey = tmp/1024;
+       DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
+}
+
+static void calc_mode_timings(int xres, int yres, int refresh,
+                             struct fb_videomode *mode)
+{
+       struct fb_var_screeninfo *var;
+
+       var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
+
+       if (var) {
+               var->xres = xres;
+               var->yres = yres;
+               fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
+                           refresh, var, NULL);
+               mode->xres = xres;
+               mode->yres = yres;
+               mode->pixclock = var->pixclock;
+               mode->refresh = refresh;
+               mode->left_margin = var->left_margin;
+               mode->right_margin = var->right_margin;
+               mode->upper_margin = var->upper_margin;
+               mode->lower_margin = var->lower_margin;
+               mode->hsync_len = var->hsync_len;
+               mode->vsync_len = var->vsync_len;
+               mode->vmode = 0;
+               mode->sync = 0;
+               kfree(var);
+       }
+}
+
+static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
+{
+       int num = 0;
+       unsigned char c;
+
+       c = block[0];
+       if (c&0x80) {
+               calc_mode_timings(720, 400, 70, &mode[num]);
+               mode[num++].flag = FB_MODE_IS_CALCULATED;
+               DPRINTK("      720x400@70Hz\n");
+       }
+       if (c&0x40) {
+               calc_mode_timings(720, 400, 88, &mode[num]);
+               mode[num++].flag = FB_MODE_IS_CALCULATED;
+               DPRINTK("      720x400@88Hz\n");
+       }
+       if (c&0x20) {
+               mode[num++] = vesa_modes[3];
+               DPRINTK("      640x480@60Hz\n");
+       }
+       if (c&0x10) {
+               calc_mode_timings(640, 480, 67, &mode[num]);
+               mode[num++].flag = FB_MODE_IS_CALCULATED;
+               DPRINTK("      640x480@67Hz\n");
+       }
+       if (c&0x08) {
+               mode[num++] = vesa_modes[4];
+               DPRINTK("      640x480@72Hz\n");
+       }
+       if (c&0x04) {
+               mode[num++] = vesa_modes[5];
+               DPRINTK("      640x480@75Hz\n");
+       }
+       if (c&0x02) {
+               mode[num++] = vesa_modes[7];
+               DPRINTK("      800x600@56Hz\n");
+       }
+       if (c&0x01) {
+               mode[num++] = vesa_modes[8];
+               DPRINTK("      800x600@60Hz\n");
+       }
+
+       c = block[1];
+       if (c&0x80) {
+               mode[num++] = vesa_modes[9];
+               DPRINTK("      800x600@72Hz\n");
+       }
+       if (c&0x40) {
+               mode[num++] = vesa_modes[10];
+               DPRINTK("      800x600@75Hz\n");
+       }
+       if (c&0x20) {
+               calc_mode_timings(832, 624, 75, &mode[num]);
+               mode[num++].flag = FB_MODE_IS_CALCULATED;
+               DPRINTK("      832x624@75Hz\n");
+       }
+       if (c&0x10) {
+               mode[num++] = vesa_modes[12];
+               DPRINTK("      1024x768@87Hz Interlaced\n");
+       }
+       if (c&0x08) {
+               mode[num++] = vesa_modes[13];
+               DPRINTK("      1024x768@60Hz\n");
+       }
+       if (c&0x04) {
+               mode[num++] = vesa_modes[14];
+               DPRINTK("      1024x768@70Hz\n");
+       }
+       if (c&0x02) {
+               mode[num++] = vesa_modes[15];
+               DPRINTK("      1024x768@75Hz\n");
+       }
+       if (c&0x01) {
+               mode[num++] = vesa_modes[21];
+               DPRINTK("      1280x1024@75Hz\n");
+       }
+       c = block[2];
+       if (c&0x80) {
+               mode[num++] = vesa_modes[17];
+               DPRINTK("      1152x870@75Hz\n");
+       }
+       DPRINTK("      Manufacturer's mask: %x\n",c&0x7F);
+       return num;
+}
+
+static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
+               int ver, int rev)
+{
+       int xres, yres = 0, refresh, ratio, i;
+
+       xres = (block[0] + 31) * 8;
+       if (xres <= 256)
+               return 0;
+
+       ratio = (block[1] & 0xc0) >> 6;
+       switch (ratio) {
+       case 0:
+               /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
+               if (ver < 1 || (ver == 1 && rev < 3))
+                       yres = xres;
+               else
+                       yres = (xres * 10)/16;
+               break;
+       case 1:
+               yres = (xres * 3)/4;
+               break;
+       case 2:
+               yres = (xres * 4)/5;
+               break;
+       case 3:
+               yres = (xres * 9)/16;
+               break;
+       }
+       refresh = (block[1] & 0x3f) + 60;
+
+       DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
+       for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+               if (vesa_modes[i].xres == xres &&
+                   vesa_modes[i].yres == yres &&
+                   vesa_modes[i].refresh == refresh) {
+                       *mode = vesa_modes[i];
+                       mode->flag |= FB_MODE_IS_STANDARD;
+                       return 1;
+               }
+       }
+       calc_mode_timings(xres, yres, refresh, mode);
+       return 1;
+}
+
+static int get_dst_timing(unsigned char *block,
+                         struct fb_videomode *mode, int ver, int rev)
+{
+       int j, num = 0;
+
+       for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
+               num += get_std_timing(block, &mode[num], ver, rev);
+
+       return num;
+}
+
+static void get_detailed_timing(unsigned char *block,
+                               struct fb_videomode *mode)
+{
+       mode->xres = H_ACTIVE;
+       mode->yres = V_ACTIVE;
+       mode->pixclock = PIXEL_CLOCK;
+       mode->pixclock /= 1000;
+       mode->pixclock = KHZ2PICOS(mode->pixclock);
+       mode->right_margin = H_SYNC_OFFSET;
+       mode->left_margin = (H_ACTIVE + H_BLANKING) -
+               (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+               V_SYNC_WIDTH;
+       mode->lower_margin = V_SYNC_OFFSET;
+       mode->hsync_len = H_SYNC_WIDTH;
+       mode->vsync_len = V_SYNC_WIDTH;
+       if (HSYNC_POSITIVE)
+               mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+       if (VSYNC_POSITIVE)
+               mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+       mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
+                                    (V_ACTIVE + V_BLANKING));
+       if (INTERLACED) {
+               mode->yres *= 2;
+               mode->upper_margin *= 2;
+               mode->lower_margin *= 2;
+               mode->vsync_len *= 2;
+               mode->vmode |= FB_VMODE_INTERLACED;
+       }
+       mode->flag = FB_MODE_IS_DETAILED;
+
+       DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
+       DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
+              H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
+       DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
+              V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
+       DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
+              (VSYNC_POSITIVE) ? "+" : "-");
+}
+
+/**
+ * fb_create_modedb - create video mode database
+ * @edid: EDID data
+ * @dbsize: database size
+ *
+ * RETURNS: struct fb_videomode, @dbsize contains length of database
+ *
+ * DESCRIPTION:
+ * This function builds a mode database using the contents of the EDID
+ * data
+ */
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+{
+       struct fb_videomode *mode, *m;
+       unsigned char *block;
+       int num = 0, i, first = 1;
+       int ver, rev;
+
+       ver = edid[EDID_STRUCT_VERSION];
+       rev = edid[EDID_STRUCT_REVISION];
+
+       mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
+       if (mode == NULL)
+               return NULL;
+
+       if (edid == NULL || !edid_checksum(edid) ||
+           !edid_check_header(edid)) {
+               kfree(mode);
+               return NULL;
+       }
+
+       *dbsize = 0;
+
+       DPRINTK("   Detailed Timings\n");
+       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+       for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+               if (!(block[0] == 0x00 && block[1] == 0x00)) {
+                       get_detailed_timing(block, &mode[num]);
+                       if (first) {
+                               mode[num].flag |= FB_MODE_IS_FIRST;
+                               first = 0;
+                       }
+                       num++;
+               }
+       }
+
+       DPRINTK("   Supported VESA Modes\n");
+       block = edid + ESTABLISHED_TIMING_1;
+       num += get_est_timing(block, &mode[num]);
+
+       DPRINTK("   Standard Timings\n");
+       block = edid + STD_TIMING_DESCRIPTIONS_START;
+       for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
+               num += get_std_timing(block, &mode[num], ver, rev);
+
+       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+       for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+               if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
+                       num += get_dst_timing(block + 5, &mode[num], ver, rev);
+       }
+
+       /* Yikes, EDID data is totally useless */
+       if (!num) {
+               kfree(mode);
+               return NULL;
+       }
+
+       *dbsize = num;
+       m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
+       if (!m)
+               return mode;
+       memmove(m, mode, num * sizeof(struct fb_videomode));
+       kfree(mode);
+       return m;
+}
+
+/**
+ * fb_destroy_modedb - destroys mode database
+ * @modedb: mode database to destroy
+ *
+ * DESCRIPTION:
+ * Destroy mode database created by fb_create_modedb
+ */
+void fb_destroy_modedb(struct fb_videomode *modedb)
+{
+       kfree(modedb);
+}
+
+static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
+{
+       int i, retval = 1;
+       unsigned char *block;
+
+       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+       DPRINTK("      Monitor Operating Limits: ");
+
+       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+               if (edid_is_limits_block(block)) {
+                       specs->hfmin = H_MIN_RATE * 1000;
+                       specs->hfmax = H_MAX_RATE * 1000;
+                       specs->vfmin = V_MIN_RATE;
+                       specs->vfmax = V_MAX_RATE;
+                       specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
+                       specs->gtf = (GTF_SUPPORT) ? 1 : 0;
+                       retval = 0;
+                       DPRINTK("From EDID\n");
+                       break;
+               }
+       }
+
+       /* estimate monitor limits based on modes supported */
+       if (retval) {
+               struct fb_videomode *modes, *mode;
+               int num_modes, hz, hscan, pixclock;
+               int vtotal, htotal;
+
+               modes = fb_create_modedb(edid, &num_modes);
+               if (!modes) {
+                       DPRINTK("None Available\n");
+                       return 1;
+               }
+
+               retval = 0;
+               for (i = 0; i < num_modes; i++) {
+                       mode = &modes[i];
+                       pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
+                       htotal = mode->xres + mode->right_margin + mode->hsync_len
+                               + mode->left_margin;
+                       vtotal = mode->yres + mode->lower_margin + mode->vsync_len
+                               + mode->upper_margin;
+
+                       if (mode->vmode & FB_VMODE_INTERLACED)
+                               vtotal /= 2;
+
+                       if (mode->vmode & FB_VMODE_DOUBLE)
+                               vtotal *= 2;
+
+                       hscan = (pixclock + htotal / 2) / htotal;
+                       hscan = (hscan + 500) / 1000 * 1000;
+                       hz = (hscan + vtotal / 2) / vtotal;
+
+                       if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
+                               specs->dclkmax = pixclock;
+
+                       if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
+                               specs->dclkmin = pixclock;
+
+                       if (specs->hfmax == 0 || specs->hfmax < hscan)
+                               specs->hfmax = hscan;
+
+                       if (specs->hfmin == 0 || specs->hfmin > hscan)
+                               specs->hfmin = hscan;
+
+                       if (specs->vfmax == 0 || specs->vfmax < hz)
+                               specs->vfmax = hz;
+
+                       if (specs->vfmin == 0 || specs->vfmin > hz)
+                               specs->vfmin = hz;
+               }
+               DPRINTK("Extrapolated\n");
+               fb_destroy_modedb(modes);
+       }
+       DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
+               specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
+               specs->vfmax, specs->dclkmax/1000000);
+       return retval;
+}
+
+static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+       unsigned char c, *block;
+
+       block = edid + EDID_STRUCT_DISPLAY;
+
+       fb_get_monitor_limits(edid, specs);
+
+       c = block[0] & 0x80;
+       specs->input = 0;
+       if (c) {
+               specs->input |= FB_DISP_DDI;
+               DPRINTK("      Digital Display Input");
+       } else {
+               DPRINTK("      Analog Display Input: Input Voltage - ");
+               switch ((block[0] & 0x60) >> 5) {
+               case 0:
+                       DPRINTK("0.700V/0.300V");
+                       specs->input |= FB_DISP_ANA_700_300;
+                       break;
+               case 1:
+                       DPRINTK("0.714V/0.286V");
+                       specs->input |= FB_DISP_ANA_714_286;
+                       break;
+               case 2:
+                       DPRINTK("1.000V/0.400V");
+                       specs->input |= FB_DISP_ANA_1000_400;
+                       break;
+               case 3:
+                       DPRINTK("0.700V/0.000V");
+                       specs->input |= FB_DISP_ANA_700_000;
+                       break;
+               }
+       }
+       DPRINTK("\n      Sync: ");
+       c = block[0] & 0x10;
+       if (c)
+               DPRINTK("      Configurable signal level\n");
+       c = block[0] & 0x0f;
+       specs->signal = 0;
+       if (c & 0x10) {
+               DPRINTK("Blank to Blank ");
+               specs->signal |= FB_SIGNAL_BLANK_BLANK;
+       }
+       if (c & 0x08) {
+               DPRINTK("Separate ");
+               specs->signal |= FB_SIGNAL_SEPARATE;
+       }
+       if (c & 0x04) {
+               DPRINTK("Composite ");
+               specs->signal |= FB_SIGNAL_COMPOSITE;
+       }
+       if (c & 0x02) {
+               DPRINTK("Sync on Green ");
+               specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
+       }
+       if (c & 0x01) {
+               DPRINTK("Serration on ");
+               specs->signal |= FB_SIGNAL_SERRATION_ON;
+       }
+       DPRINTK("\n");
+       specs->max_x = block[1];
+       specs->max_y = block[2];
+       DPRINTK("      Max H-size in cm: ");
+       if (specs->max_x)
+               DPRINTK("%d\n", specs->max_x);
+       else
+               DPRINTK("variable\n");
+       DPRINTK("      Max V-size in cm: ");
+       if (specs->max_y)
+               DPRINTK("%d\n", specs->max_y);
+       else
+               DPRINTK("variable\n");
+
+       c = block[3];
+       specs->gamma = c+100;
+       DPRINTK("      Gamma: ");
+       DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
+
+       get_dpms_capabilities(block[4], specs);
+
+       switch ((block[4] & 0x18) >> 3) {
+       case 0:
+               DPRINTK("      Monochrome/Grayscale\n");
+               specs->input |= FB_DISP_MONO;
+               break;
+       case 1:
+               DPRINTK("      RGB Color Display\n");
+               specs->input |= FB_DISP_RGB;
+               break;
+       case 2:
+               DPRINTK("      Non-RGB Multicolor Display\n");
+               specs->input |= FB_DISP_MULTI;
+               break;
+       default:
+               DPRINTK("      Unknown\n");
+               specs->input |= FB_DISP_UNKNOWN;
+               break;
+       }
+
+       get_chroma(block, specs);
+
+       specs->misc = 0;
+       c = block[4] & 0x7;
+       if (c & 0x04) {
+               DPRINTK("      Default color format is primary\n");
+               specs->misc |= FB_MISC_PRIM_COLOR;
+       }
+       if (c & 0x02) {
+               DPRINTK("      First DETAILED Timing is preferred\n");
+               specs->misc |= FB_MISC_1ST_DETAIL;
+       }
+       if (c & 0x01) {
+               printk("      Display is GTF capable\n");
+               specs->gtf = 1;
+       }
+}
+
+int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
+{
+       int i;
+       unsigned char *block;
+
+       if (edid == NULL || var == NULL)
+               return 1;
+
+       if (!(edid_checksum(edid)))
+               return 1;
+
+       if (!(edid_check_header(edid)))
+               return 1;
+
+       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+
+       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+               if (edid_is_timing_block(block)) {
+                       var->xres = var->xres_virtual = H_ACTIVE;
+                       var->yres = var->yres_virtual = V_ACTIVE;
+                       var->height = var->width = 0;
+                       var->right_margin = H_SYNC_OFFSET;
+                       var->left_margin = (H_ACTIVE + H_BLANKING) -
+                               (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+                       var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+                               V_SYNC_WIDTH;
+                       var->lower_margin = V_SYNC_OFFSET;
+                       var->hsync_len = H_SYNC_WIDTH;
+                       var->vsync_len = V_SYNC_WIDTH;
+                       var->pixclock = PIXEL_CLOCK;
+                       var->pixclock /= 1000;
+                       var->pixclock = KHZ2PICOS(var->pixclock);
+
+                       if (HSYNC_POSITIVE)
+                               var->sync |= FB_SYNC_HOR_HIGH_ACT;
+                       if (VSYNC_POSITIVE)
+                               var->sync |= FB_SYNC_VERT_HIGH_ACT;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+       unsigned char *block;
+       int i, found = 0;
+
+       if (edid == NULL)
+               return;
+
+       if (!(edid_checksum(edid)))
+               return;
+
+       if (!(edid_check_header(edid)))
+               return;
+
+       memset(specs, 0, sizeof(struct fb_monspecs));
+
+       specs->version = edid[EDID_STRUCT_VERSION];
+       specs->revision = edid[EDID_STRUCT_REVISION];
+
+       DPRINTK("========================================\n");
+       DPRINTK("Display Information (EDID)\n");
+       DPRINTK("========================================\n");
+       DPRINTK("   EDID Version %d.%d\n", (int) specs->version,
+              (int) specs->revision);
+
+       parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
+
+       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
+               if (edid_is_serial_block(block)) {
+                       copy_string(block, specs->serial_no);
+                       DPRINTK("   Serial Number: %s\n", specs->serial_no);
+               } else if (edid_is_ascii_block(block)) {
+                       copy_string(block, specs->ascii);
+                       DPRINTK("   ASCII Block: %s\n", specs->ascii);
+               } else if (edid_is_monitor_block(block)) {
+                       copy_string(block, specs->monitor);
+                       DPRINTK("   Monitor Name: %s\n", specs->monitor);
+               }
+       }
+
+       DPRINTK("   Display Characteristics:\n");
+       get_monspecs(edid, specs);
+
+       specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
+
+       /*
+        * Workaround for buggy EDIDs that sets that the first
+        * detailed timing is preferred but has not detailed
+        * timing specified
+        */
+       for (i = 0; i < specs->modedb_len; i++) {
+               if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               specs->misc &= ~FB_MISC_1ST_DETAIL;
+
+       DPRINTK("========================================\n");
+}
+
+/**
+ * fb_edid_add_monspecs() - add monitor video modes from E-EDID data
+ * @edid:      128 byte array with an E-EDID block
+ * @spacs:     monitor specs to be extended
+ */
+void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+       unsigned char *block;
+       struct fb_videomode *m;
+       int num = 0, i;
+       u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE];
+       u8 pos = 4, svd_n = 0;
+
+       if (!edid)
+               return;
+
+       if (!edid_checksum(edid))
+               return;
+
+       if (edid[0] != 0x2 ||
+           edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
+               return;
+
+       DPRINTK("  Short Video Descriptors\n");
+
+       while (pos < edid[2]) {
+               u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
+               pr_debug("Data block %u of %u bytes\n", type, len);
+               if (type == 2)
+                       for (i = pos; i < pos + len; i++) {
+                               u8 idx = edid[pos + i] & 0x7f;
+                               svd[svd_n++] = idx;
+                               pr_debug("N%sative mode #%d\n",
+                                        edid[pos + i] & 0x80 ? "" : "on-n", idx);
+                       }
+               pos += len + 1;
+       }
+
+       block = edid + edid[2];
+
+       DPRINTK("  Extended Detailed Timings\n");
+
+       for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE;
+            i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
+               if (PIXEL_CLOCK)
+                       edt[num++] = block - edid;
+
+       /* Yikes, EDID data is totally useless */
+       if (!(num + svd_n))
+               return;
+
+       m = kzalloc((specs->modedb_len + num + svd_n) *
+                      sizeof(struct fb_videomode), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode));
+
+       for (i = specs->modedb_len; i < specs->modedb_len + num; i++) {
+               get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]);
+               if (i == specs->modedb_len)
+                       m[i].flag |= FB_MODE_IS_FIRST;
+               pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh);
+       }
+
+       for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) {
+               int idx = svd[i - specs->modedb_len - num];
+               if (!idx || idx > 63) {
+                       pr_warning("Reserved SVD code %d\n", idx);
+               } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) {
+                       pr_warning("Unimplemented SVD code %d\n", idx);
+               } else {
+                       memcpy(&m[i], cea_modes + idx, sizeof(m[i]));
+                       pr_debug("Adding SVD #%d: %ux%u@%u\n", idx,
+                                m[i].xres, m[i].yres, m[i].refresh);
+               }
+       }
+
+       kfree(specs->modedb);
+       specs->modedb = m;
+       specs->modedb_len = specs->modedb_len + num + svd_n;
+}
+
+/*
+ * VESA Generalized Timing Formula (GTF)
+ */
+
+#define FLYBACK                     550
+#define V_FRONTPORCH                1
+#define H_OFFSET                    40
+#define H_SCALEFACTOR               20
+#define H_BLANKSCALE                128
+#define H_GRADIENT                  600
+#define C_VAL                       30
+#define M_VAL                       300
+
+struct __fb_timings {
+       u32 dclk;
+       u32 hfreq;
+       u32 vfreq;
+       u32 hactive;
+       u32 vactive;
+       u32 hblank;
+       u32 vblank;
+       u32 htotal;
+       u32 vtotal;
+};
+
+/**
+ * fb_get_vblank - get vertical blank time
+ * @hfreq: horizontal freq
+ *
+ * DESCRIPTION:
+ * vblank = right_margin + vsync_len + left_margin
+ *
+ *    given: right_margin = 1 (V_FRONTPORCH)
+ *           vsync_len    = 3
+ *           flyback      = 550
+ *
+ *                          flyback * hfreq
+ *           left_margin  = --------------- - vsync_len
+ *                           1000000
+ */
+static u32 fb_get_vblank(u32 hfreq)
+{
+       u32 vblank;
+
+       vblank = (hfreq * FLYBACK)/1000;
+       vblank = (vblank + 500)/1000;
+       return (vblank + V_FRONTPORCH);
+}
+
+/**
+ * fb_get_hblank_by_freq - get horizontal blank time given hfreq
+ * @hfreq: horizontal freq
+ * @xres: horizontal resolution in pixels
+ *
+ * DESCRIPTION:
+ *
+ *           xres * duty_cycle
+ * hblank = ------------------
+ *           100 - duty_cycle
+ *
+ * duty cycle = percent of htotal assigned to inactive display
+ * duty cycle = C - (M/Hfreq)
+ *
+ * where: C = ((offset - scale factor) * blank_scale)
+ *            -------------------------------------- + scale factor
+ *                        256
+ *        M = blank_scale * gradient
+ *
+ */
+static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
+{
+       u32 c_val, m_val, duty_cycle, hblank;
+
+       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
+                H_SCALEFACTOR) * 1000;
+       m_val = (H_BLANKSCALE * H_GRADIENT)/256;
+       m_val = (m_val * 1000000)/hfreq;
+       duty_cycle = c_val - m_val;
+       hblank = (xres * duty_cycle)/(100000 - duty_cycle);
+       return (hblank);
+}
+
+/**
+ * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
+ * @dclk: pixelclock in Hz
+ * @xres: horizontal resolution in pixels
+ *
+ * DESCRIPTION:
+ *
+ *           xres * duty_cycle
+ * hblank = ------------------
+ *           100 - duty_cycle
+ *
+ * duty cycle = percent of htotal assigned to inactive display
+ * duty cycle = C - (M * h_period)
+ *
+ * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
+ *                   -----------------------------------------------
+ *                                    2 * M
+ *        M = 300;
+ *        C = 30;
+
+ */
+static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
+{
+       u32 duty_cycle, h_period, hblank;
+
+       dclk /= 1000;
+       h_period = 100 - C_VAL;
+       h_period *= h_period;
+       h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
+       h_period *= 10000;
+
+       h_period = int_sqrt(h_period);
+       h_period -= (100 - C_VAL) * 100;
+       h_period *= 1000;
+       h_period /= 2 * M_VAL;
+
+       duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
+       hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
+       hblank &= ~15;
+       return (hblank);
+}
+
+/**
+ * fb_get_hfreq - estimate hsync
+ * @vfreq: vertical refresh rate
+ * @yres: vertical resolution
+ *
+ * DESCRIPTION:
+ *
+ *          (yres + front_port) * vfreq * 1000000
+ * hfreq = -------------------------------------
+ *          (1000000 - (vfreq * FLYBACK)
+ *
+ */
+
+static u32 fb_get_hfreq(u32 vfreq, u32 yres)
+{
+       u32 divisor, hfreq;
+
+       divisor = (1000000 - (vfreq * FLYBACK))/1000;
+       hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
+       return (hfreq/divisor);
+}
+
+static void fb_timings_vfreq(struct __fb_timings *timings)
+{
+       timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
+       timings->vblank = fb_get_vblank(timings->hfreq);
+       timings->vtotal = timings->vactive + timings->vblank;
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+                                                timings->hactive);
+       timings->htotal = timings->hactive + timings->hblank;
+       timings->dclk = timings->htotal * timings->hfreq;
+}
+
+static void fb_timings_hfreq(struct __fb_timings *timings)
+{
+       timings->vblank = fb_get_vblank(timings->hfreq);
+       timings->vtotal = timings->vactive + timings->vblank;
+       timings->vfreq = timings->hfreq/timings->vtotal;
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+                                                timings->hactive);
+       timings->htotal = timings->hactive + timings->hblank;
+       timings->dclk = timings->htotal * timings->hfreq;
+}
+
+static void fb_timings_dclk(struct __fb_timings *timings)
+{
+       timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
+                                               timings->hactive);
+       timings->htotal = timings->hactive + timings->hblank;
+       timings->hfreq = timings->dclk/timings->htotal;
+       timings->vblank = fb_get_vblank(timings->hfreq);
+       timings->vtotal = timings->vactive + timings->vblank;
+       timings->vfreq = timings->hfreq/timings->vtotal;
+}
+
+/*
+ * fb_get_mode - calculates video mode using VESA GTF
+ * @flags: if: 0 - maximize vertical refresh rate
+ *             1 - vrefresh-driven calculation;
+ *             2 - hscan-driven calculation;
+ *             3 - pixelclock-driven calculation;
+ * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
+ * @var: pointer to fb_var_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * Calculates video mode based on monitor specs using VESA GTF.
+ * The GTF is best for VESA GTF compliant monitors but is
+ * specifically formulated to work for older monitors as well.
+ *
+ * If @flag==0, the function will attempt to maximize the
+ * refresh rate.  Otherwise, it will calculate timings based on
+ * the flag and accompanying value.
+ *
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be
+ * ignored and @var will be filled with the calculated timings.
+ *
+ * All calculations are based on the VESA GTF Spreadsheet
+ * available at VESA's public ftp (http://www.vesa.org).
+ *
+ * NOTES:
+ * The timings generated by the GTF will be different from VESA
+ * DMT.  It might be a good idea to keep a table of standard
+ * VESA modes as well.  The GTF may also not work for some displays,
+ * such as, and especially, analog TV.
+ *
+ * REQUIRES:
+ * A valid info->monspecs, otherwise 'safe numbers' will be used.
+ */
+int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct __fb_timings *timings;
+       u32 interlace = 1, dscan = 1;
+       u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
+
+
+       timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
+
+       if (!timings)
+               return -ENOMEM;
+
+       /*
+        * If monspecs are invalid, use values that are enough
+        * for 640x480@60
+        */
+       if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
+           !info->monspecs.dclkmax ||
+           info->monspecs.hfmax < info->monspecs.hfmin ||
+           info->monspecs.vfmax < info->monspecs.vfmin ||
+           info->monspecs.dclkmax < info->monspecs.dclkmin) {
+               hfmin = 29000; hfmax = 30000;
+               vfmin = 60; vfmax = 60;
+               dclkmin = 0; dclkmax = 25000000;
+       } else {
+               hfmin = info->monspecs.hfmin;
+               hfmax = info->monspecs.hfmax;
+               vfmin = info->monspecs.vfmin;
+               vfmax = info->monspecs.vfmax;
+               dclkmin = info->monspecs.dclkmin;
+               dclkmax = info->monspecs.dclkmax;
+       }
+
+       timings->hactive = var->xres;
+       timings->vactive = var->yres;
+       if (var->vmode & FB_VMODE_INTERLACED) {
+               timings->vactive /= 2;
+               interlace = 2;
+       }
+       if (var->vmode & FB_VMODE_DOUBLE) {
+               timings->vactive *= 2;
+               dscan = 2;
+       }
+
+       switch (flags & ~FB_IGNOREMON) {
+       case FB_MAXTIMINGS: /* maximize refresh rate */
+               timings->hfreq = hfmax;
+               fb_timings_hfreq(timings);
+               if (timings->vfreq > vfmax) {
+                       timings->vfreq = vfmax;
+                       fb_timings_vfreq(timings);
+               }
+               if (timings->dclk > dclkmax) {
+                       timings->dclk = dclkmax;
+                       fb_timings_dclk(timings);
+               }
+               break;
+       case FB_VSYNCTIMINGS: /* vrefresh driven */
+               timings->vfreq = val;
+               fb_timings_vfreq(timings);
+               break;
+       case FB_HSYNCTIMINGS: /* hsync driven */
+               timings->hfreq = val;
+               fb_timings_hfreq(timings);
+               break;
+       case FB_DCLKTIMINGS: /* pixelclock driven */
+               timings->dclk = PICOS2KHZ(val) * 1000;
+               fb_timings_dclk(timings);
+               break;
+       default:
+               err = -EINVAL;
+
+       }
+
+       if (err || (!(flags & FB_IGNOREMON) &&
+           (timings->vfreq < vfmin || timings->vfreq > vfmax ||
+            timings->hfreq < hfmin || timings->hfreq > hfmax ||
+            timings->dclk < dclkmin || timings->dclk > dclkmax))) {
+               err = -EINVAL;
+       } else {
+               var->pixclock = KHZ2PICOS(timings->dclk/1000);
+               var->hsync_len = (timings->htotal * 8)/100;
+               var->right_margin = (timings->hblank/2) - var->hsync_len;
+               var->left_margin = timings->hblank - var->right_margin -
+                       var->hsync_len;
+               var->vsync_len = (3 * interlace)/dscan;
+               var->lower_margin = (1 * interlace)/dscan;
+               var->upper_margin = (timings->vblank * interlace)/dscan -
+                       (var->vsync_len + var->lower_margin);
+       }
+
+       kfree(timings);
+       return err;
+}
+
+#ifdef CONFIG_VIDEOMODE_HELPERS
+int fb_videomode_from_videomode(const struct videomode *vm,
+                               struct fb_videomode *fbmode)
+{
+       unsigned int htotal, vtotal;
+
+       fbmode->xres = vm->hactive;
+       fbmode->left_margin = vm->hback_porch;
+       fbmode->right_margin = vm->hfront_porch;
+       fbmode->hsync_len = vm->hsync_len;
+
+       fbmode->yres = vm->vactive;
+       fbmode->upper_margin = vm->vback_porch;
+       fbmode->lower_margin = vm->vfront_porch;
+       fbmode->vsync_len = vm->vsync_len;
+
+       /* prevent division by zero in KHZ2PICOS macro */
+       fbmode->pixclock = vm->pixelclock ?
+                       KHZ2PICOS(vm->pixelclock / 1000) : 0;
+
+       fbmode->sync = 0;
+       fbmode->vmode = 0;
+       if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+               fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
+       if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+               fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
+       if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+               fbmode->vmode |= FB_VMODE_INTERLACED;
+       if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
+               fbmode->vmode |= FB_VMODE_DOUBLE;
+       fbmode->flag = 0;
+
+       htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
+                vm->hsync_len;
+       vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
+                vm->vsync_len;
+       /* prevent division by zero */
+       if (htotal && vtotal) {
+               fbmode->refresh = vm->pixelclock / (htotal * vtotal);
+       /* a mode must have htotal and vtotal != 0 or it is invalid */
+       } else {
+               fbmode->refresh = 0;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
+
+#ifdef CONFIG_OF
+static inline void dump_fb_videomode(const struct fb_videomode *m)
+{
+       pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
+                m->xres, m->yres, m->refresh, m->pixclock, m->left_margin,
+                m->right_margin, m->upper_margin, m->lower_margin,
+                m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
+
+/**
+ * of_get_fb_videomode - get a fb_videomode from devicetree
+ * @np: device_node with the timing specification
+ * @fb: will be set to the return value
+ * @index: index into the list of display timings in devicetree
+ *
+ * DESCRIPTION:
+ * This function is expensive and should only be used, if only one mode is to be
+ * read from DT. To get multiple modes start with of_get_display_timings ond
+ * work with that instead.
+ */
+int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
+                       int index)
+{
+       struct videomode vm;
+       int ret;
+
+       ret = of_get_videomode(np, &vm, index);
+       if (ret)
+               return ret;
+
+       fb_videomode_from_videomode(&vm, fb);
+
+       pr_debug("%s: got %dx%d display mode from %s\n",
+               of_node_full_name(np), vm.hactive, vm.vactive, np->name);
+       dump_fb_videomode(fb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_get_fb_videomode);
+#endif /* CONFIG_OF */
+#endif /* CONFIG_VIDEOMODE_HELPERS */
+
+#else
+int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
+{
+       return 1;
+}
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+       specs = NULL;
+}
+void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+}
+void fb_destroy_modedb(struct fb_videomode *modedb)
+{
+}
+int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
+               struct fb_info *info)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_FB_MODE_HELPERS */
+
+/*
+ * fb_validate_mode - validates var against monitor capabilities
+ * @var: pointer to fb_var_screeninfo
+ * @info: pointer to fb_info
+ *
+ * DESCRIPTION:
+ * Validates video mode against monitor capabilities specified in
+ * info->monspecs.
+ *
+ * REQUIRES:
+ * A valid info->monspecs.
+ */
+int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       u32 hfreq, vfreq, htotal, vtotal, pixclock;
+       u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
+
+       /*
+        * If monspecs are invalid, use values that are enough
+        * for 640x480@60
+        */
+       if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+           !info->monspecs.dclkmax ||
+           info->monspecs.hfmax < info->monspecs.hfmin ||
+           info->monspecs.vfmax < info->monspecs.vfmin ||
+           info->monspecs.dclkmax < info->monspecs.dclkmin) {
+               hfmin = 29000; hfmax = 30000;
+               vfmin = 60; vfmax = 60;
+               dclkmin = 0; dclkmax = 25000000;
+       } else {
+               hfmin = info->monspecs.hfmin;
+               hfmax = info->monspecs.hfmax;
+               vfmin = info->monspecs.vfmin;
+               vfmax = info->monspecs.vfmax;
+               dclkmin = info->monspecs.dclkmin;
+               dclkmax = info->monspecs.dclkmax;
+       }
+
+       if (!var->pixclock)
+               return -EINVAL;
+       pixclock = PICOS2KHZ(var->pixclock) * 1000;
+
+       htotal = var->xres + var->right_margin + var->hsync_len +
+               var->left_margin;
+       vtotal = var->yres + var->lower_margin + var->vsync_len +
+               var->upper_margin;
+
+       if (var->vmode & FB_VMODE_INTERLACED)
+               vtotal /= 2;
+       if (var->vmode & FB_VMODE_DOUBLE)
+               vtotal *= 2;
+
+       hfreq = pixclock/htotal;
+       hfreq = (hfreq + 500) / 1000 * 1000;
+
+       vfreq = hfreq/vtotal;
+
+       return (vfreq < vfmin || vfreq > vfmax ||
+               hfreq < hfmin || hfreq > hfmax ||
+               pixclock < dclkmin || pixclock > dclkmax) ?
+               -EINVAL : 0;
+}
+
+#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
+
+/*
+ * We need to ensure that the EDID block is only returned for
+ * the primary graphics adapter.
+ */
+
+const unsigned char *fb_firmware_edid(struct device *device)
+{
+       struct pci_dev *dev = NULL;
+       struct resource *res = NULL;
+       unsigned char *edid = NULL;
+
+       if (device)
+               dev = to_pci_dev(device);
+
+       if (dev)
+               res = &dev->resource[PCI_ROM_RESOURCE];
+
+       if (res && res->flags & IORESOURCE_ROM_SHADOW)
+               edid = edid_info.dummy;
+
+       return edid;
+}
+#else
+const unsigned char *fb_firmware_edid(struct device *device)
+{
+       return NULL;
+}
+#endif
+EXPORT_SYMBOL(fb_firmware_edid);
+
+EXPORT_SYMBOL(fb_parse_edid);
+EXPORT_SYMBOL(fb_edid_to_monspecs);
+EXPORT_SYMBOL(fb_edid_add_monspecs);
+EXPORT_SYMBOL(fb_get_mode);
+EXPORT_SYMBOL(fb_validate_mode);
+EXPORT_SYMBOL(fb_destroy_modedb);
diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
new file mode 100644 (file)
index 0000000..53444ac
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * fbsysfs.c - framebuffer device class and attributes
+ *
+ * Copyright (c) 2004 James Simmons <jsimmons@infradead.org>
+ * 
+ *     This program is free software you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Note:  currently there's only stubs for framebuffer_alloc and
+ * framebuffer_release here.  The reson for that is that until all drivers
+ * are converted to use it a sysfsification will open OOPSable races.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/module.h>
+
+#define FB_SYSFS_FLAG_ATTR 1
+
+/**
+ * framebuffer_alloc - creates a new frame buffer info structure
+ *
+ * @size: size of driver private data, can be zero
+ * @dev: pointer to the device for this fb, this can be NULL
+ *
+ * Creates a new frame buffer info structure. Also reserves @size bytes
+ * for driver private data (info->par). info->par (if any) will be
+ * aligned to sizeof(long).
+ *
+ * Returns the new structure, or NULL if an error occurred.
+ *
+ */
+struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
+{
+#define BYTES_PER_LONG (BITS_PER_LONG/8)
+#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
+       int fb_info_size = sizeof(struct fb_info);
+       struct fb_info *info;
+       char *p;
+
+       if (size)
+               fb_info_size += PADDING;
+
+       p = kzalloc(fb_info_size + size, GFP_KERNEL);
+
+       if (!p)
+               return NULL;
+
+       info = (struct fb_info *) p;
+
+       if (size)
+               info->par = p + fb_info_size;
+
+       info->device = dev;
+
+#ifdef CONFIG_FB_BACKLIGHT
+       mutex_init(&info->bl_curve_mutex);
+#endif
+
+       return info;
+#undef PADDING
+#undef BYTES_PER_LONG
+}
+EXPORT_SYMBOL(framebuffer_alloc);
+
+/**
+ * framebuffer_release - marks the structure available for freeing
+ *
+ * @info: frame buffer info structure
+ *
+ * Drop the reference count of the device embedded in the
+ * framebuffer info structure.
+ *
+ */
+void framebuffer_release(struct fb_info *info)
+{
+       if (!info)
+               return;
+       kfree(info->apertures);
+       kfree(info);
+}
+EXPORT_SYMBOL(framebuffer_release);
+
+static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
+{
+       int err;
+
+       var->activate |= FB_ACTIVATE_FORCE;
+       console_lock();
+       fb_info->flags |= FBINFO_MISC_USEREVENT;
+       err = fb_set_var(fb_info, var);
+       fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+       console_unlock();
+       if (err)
+               return err;
+       return 0;
+}
+
+static int mode_string(char *buf, unsigned int offset,
+                      const struct fb_videomode *mode)
+{
+       char m = 'U';
+       char v = 'p';
+
+       if (mode->flag & FB_MODE_IS_DETAILED)
+               m = 'D';
+       if (mode->flag & FB_MODE_IS_VESA)
+               m = 'V';
+       if (mode->flag & FB_MODE_IS_STANDARD)
+               m = 'S';
+
+       if (mode->vmode & FB_VMODE_INTERLACED)
+               v = 'i';
+       if (mode->vmode & FB_VMODE_DOUBLE)
+               v = 'd';
+
+       return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
+                       m, mode->xres, mode->yres, v, mode->refresh);
+}
+
+static ssize_t store_mode(struct device *device, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       char mstr[100];
+       struct fb_var_screeninfo var;
+       struct fb_modelist *modelist;
+       struct fb_videomode *mode;
+       struct list_head *pos;
+       size_t i;
+       int err;
+
+       memset(&var, 0, sizeof(var));
+
+       list_for_each(pos, &fb_info->modelist) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               mode = &modelist->mode;
+               i = mode_string(mstr, 0, mode);
+               if (strncmp(mstr, buf, max(count, i)) == 0) {
+
+                       var = fb_info->var;
+                       fb_videomode_to_var(&var, mode);
+                       if ((err = activate(fb_info, &var)))
+                               return err;
+                       fb_info->mode = mode;
+                       return count;
+               }
+       }
+       return -EINVAL;
+}
+
+static ssize_t show_mode(struct device *device, struct device_attribute *attr,
+                        char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+
+       if (!fb_info->mode)
+               return 0;
+
+       return mode_string(buf, 0, fb_info->mode);
+}
+
+static ssize_t store_modes(struct device *device,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       LIST_HEAD(old_list);
+       int i = count / sizeof(struct fb_videomode);
+
+       if (i * sizeof(struct fb_videomode) != count)
+               return -EINVAL;
+
+       console_lock();
+       if (!lock_fb_info(fb_info)) {
+               console_unlock();
+               return -ENODEV;
+       }
+
+       list_splice(&fb_info->modelist, &old_list);
+       fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
+                                &fb_info->modelist);
+       if (fb_new_modelist(fb_info)) {
+               fb_destroy_modelist(&fb_info->modelist);
+               list_splice(&old_list, &fb_info->modelist);
+       } else
+               fb_destroy_modelist(&old_list);
+
+       unlock_fb_info(fb_info);
+       console_unlock();
+
+       return 0;
+}
+
+static ssize_t show_modes(struct device *device, struct device_attribute *attr,
+                         char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       unsigned int i;
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       const struct fb_videomode *mode;
+
+       i = 0;
+       list_for_each(pos, &fb_info->modelist) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               mode = &modelist->mode;
+               i += mode_string(buf, i, mode);
+       }
+       return i;
+}
+
+static ssize_t store_bpp(struct device *device, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       struct fb_var_screeninfo var;
+       char ** last = NULL;
+       int err;
+
+       var = fb_info->var;
+       var.bits_per_pixel = simple_strtoul(buf, last, 0);
+       if ((err = activate(fb_info, &var)))
+               return err;
+       return count;
+}
+
+static ssize_t show_bpp(struct device *device, struct device_attribute *attr,
+                       char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
+}
+
+static ssize_t store_rotate(struct device *device,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       struct fb_var_screeninfo var;
+       char **last = NULL;
+       int err;
+
+       var = fb_info->var;
+       var.rotate = simple_strtoul(buf, last, 0);
+
+       if ((err = activate(fb_info, &var)))
+               return err;
+
+       return count;
+}
+
+
+static ssize_t show_rotate(struct device *device,
+                          struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
+}
+
+static ssize_t store_virtual(struct device *device,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       struct fb_var_screeninfo var;
+       char *last = NULL;
+       int err;
+
+       var = fb_info->var;
+       var.xres_virtual = simple_strtoul(buf, &last, 0);
+       last++;
+       if (last - buf >= count)
+               return -EINVAL;
+       var.yres_virtual = simple_strtoul(last, &last, 0);
+
+       if ((err = activate(fb_info, &var)))
+               return err;
+       return count;
+}
+
+static ssize_t show_virtual(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
+                       fb_info->var.yres_virtual);
+}
+
+static ssize_t show_stride(struct device *device,
+                          struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length);
+}
+
+static ssize_t store_blank(struct device *device,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       char *last = NULL;
+       int err;
+
+       console_lock();
+       fb_info->flags |= FBINFO_MISC_USEREVENT;
+       err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
+       fb_info->flags &= ~FBINFO_MISC_USEREVENT;
+       console_unlock();
+       if (err < 0)
+               return err;
+       return count;
+}
+
+static ssize_t show_blank(struct device *device,
+                         struct device_attribute *attr, char *buf)
+{
+//     struct fb_info *fb_info = dev_get_drvdata(device);
+       return 0;
+}
+
+static ssize_t store_console(struct device *device,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+//     struct fb_info *fb_info = dev_get_drvdata(device);
+       return 0;
+}
+
+static ssize_t show_console(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+//     struct fb_info *fb_info = dev_get_drvdata(device);
+       return 0;
+}
+
+static ssize_t store_cursor(struct device *device,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+//     struct fb_info *fb_info = dev_get_drvdata(device);
+       return 0;
+}
+
+static ssize_t show_cursor(struct device *device,
+                          struct device_attribute *attr, char *buf)
+{
+//     struct fb_info *fb_info = dev_get_drvdata(device);
+       return 0;
+}
+
+static ssize_t store_pan(struct device *device,
+                        struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       struct fb_var_screeninfo var;
+       char *last = NULL;
+       int err;
+
+       var = fb_info->var;
+       var.xoffset = simple_strtoul(buf, &last, 0);
+       last++;
+       if (last - buf >= count)
+               return -EINVAL;
+       var.yoffset = simple_strtoul(last, &last, 0);
+
+       console_lock();
+       err = fb_pan_display(fb_info, &var);
+       console_unlock();
+
+       if (err < 0)
+               return err;
+       return count;
+}
+
+static ssize_t show_pan(struct device *device,
+                       struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
+                       fb_info->var.yoffset);
+}
+
+static ssize_t show_name(struct device *device,
+                        struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id);
+}
+
+static ssize_t store_fbstate(struct device *device,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       u32 state;
+       char *last = NULL;
+
+       state = simple_strtoul(buf, &last, 0);
+
+       console_lock();
+       if (!lock_fb_info(fb_info)) {
+               console_unlock();
+               return -ENODEV;
+       }
+
+       fb_set_suspend(fb_info, (int)state);
+
+       unlock_fb_info(fb_info);
+       console_unlock();
+
+       return count;
+}
+
+static ssize_t show_fbstate(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
+}
+
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct device *device,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+       unsigned int i;
+
+       /* Some drivers don't use framebuffer_alloc(), but those also
+        * don't have backlights.
+        */
+       if (!fb_info || !fb_info->bl_dev)
+               return -ENODEV;
+
+       if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+               return -EINVAL;
+
+       for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+               if (sscanf(&buf[i * 24],
+                       "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+                       &tmp_curve[i * 8 + 0],
+                       &tmp_curve[i * 8 + 1],
+                       &tmp_curve[i * 8 + 2],
+                       &tmp_curve[i * 8 + 3],
+                       &tmp_curve[i * 8 + 4],
+                       &tmp_curve[i * 8 + 5],
+                       &tmp_curve[i * 8 + 6],
+                       &tmp_curve[i * 8 + 7]) != 8)
+                       return -EINVAL;
+
+       /* If there has been an error in the input data, we won't
+        * reach this loop.
+        */
+       mutex_lock(&fb_info->bl_curve_mutex);
+       for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+               fb_info->bl_curve[i] = tmp_curve[i];
+       mutex_unlock(&fb_info->bl_curve_mutex);
+
+       return count;
+}
+
+static ssize_t show_bl_curve(struct device *device,
+                            struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fb_info = dev_get_drvdata(device);
+       ssize_t len = 0;
+       unsigned int i;
+
+       /* Some drivers don't use framebuffer_alloc(), but those also
+        * don't have backlights.
+        */
+       if (!fb_info || !fb_info->bl_dev)
+               return -ENODEV;
+
+       mutex_lock(&fb_info->bl_curve_mutex);
+       for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+               len += snprintf(&buf[len], PAGE_SIZE,
+                               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+                               fb_info->bl_curve[i + 0],
+                               fb_info->bl_curve[i + 1],
+                               fb_info->bl_curve[i + 2],
+                               fb_info->bl_curve[i + 3],
+                               fb_info->bl_curve[i + 4],
+                               fb_info->bl_curve[i + 5],
+                               fb_info->bl_curve[i + 6],
+                               fb_info->bl_curve[i + 7]);
+       mutex_unlock(&fb_info->bl_curve_mutex);
+
+       return len;
+}
+#endif
+
+/* When cmap is added back in it should be a binary attribute
+ * not a text one. Consideration should also be given to converting
+ * fbdev to use configfs instead of sysfs */
+static struct device_attribute device_attrs[] = {
+       __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
+       __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
+       __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
+       __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
+       __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
+       __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+       __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+       __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
+       __ATTR(name, S_IRUGO, show_name, NULL),
+       __ATTR(stride, S_IRUGO, show_stride, NULL),
+       __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+       __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+       __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
+};
+
+int fb_init_device(struct fb_info *fb_info)
+{
+       int i, error = 0;
+
+       dev_set_drvdata(fb_info->dev, fb_info);
+
+       fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
+
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+               error = device_create_file(fb_info->dev, &device_attrs[i]);
+
+               if (error)
+                       break;
+       }
+
+       if (error) {
+               while (--i >= 0)
+                       device_remove_file(fb_info->dev, &device_attrs[i]);
+               fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
+       }
+
+       return 0;
+}
+
+void fb_cleanup_device(struct fb_info *fb_info)
+{
+       unsigned int i;
+
+       if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
+               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+                       device_remove_file(fb_info->dev, &device_attrs[i]);
+
+               fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
+       }
+}
+
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ *     0: off
+ *   1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+       unsigned int i, flat, count, range = (max - min);
+
+       mutex_lock(&fb_info->bl_curve_mutex);
+
+       fb_info->bl_curve[0] = off;
+
+       for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+               fb_info->bl_curve[flat] = min;
+
+       count = FB_BACKLIGHT_LEVELS * 15 / 16;
+       for (i = 0; i < count; ++i)
+               fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+
+       mutex_unlock(&fb_info->bl_curve_mutex);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
new file mode 100644 (file)
index 0000000..a9a907c
--- /dev/null
@@ -0,0 +1,1137 @@
+/*
+ *  linux/drivers/video/modedb.c -- Standard video mode database management
+ *
+ *     Copyright (C) 1999 Geert Uytterhoeven
+ *
+ *     2001 - Documented with DocBook
+ *     - Brad Douglas <brad@neruo.com>
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+
+#undef DEBUG
+
+#define name_matches(v, s, l) \
+    ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
+#define res_matches(v, x, y) \
+    ((v).xres == (x) && (v).yres == (y))
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...)  printk("modedb %s: " fmt, __func__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+const char *fb_mode_option;
+EXPORT_SYMBOL_GPL(fb_mode_option);
+
+/*
+ *  Standard video mode definitions (taken from XFree86)
+ */
+
+static const struct fb_videomode modedb[] = {
+
+       /* 640x400 @ 70 Hz, 31.5 kHz hsync */
+       { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 640x480 @ 60 Hz, 31.5 kHz hsync */
+       { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,     0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 800x600 @ 56 Hz, 35.15 kHz hsync */
+       { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,     0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
+       { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0,
+               FB_VMODE_INTERLACED },
+
+       /* 640x400 @ 85 Hz, 37.86 kHz hsync */
+       { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
+               FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+
+       /* 640x480 @ 72 Hz, 36.5 kHz hsync */
+       { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 640x480 @ 75 Hz, 37.50 kHz hsync */
+       { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,     0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 800x600 @ 60 Hz, 37.8 kHz hsync */
+       { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 640x480 @ 85 Hz, 43.27 kHz hsync */
+       { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
+       { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0,
+               FB_VMODE_INTERLACED },
+       /* 800x600 @ 72 Hz, 48.0 kHz hsync */
+       { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 60 Hz, 48.4 kHz hsync */
+       { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 640x480 @ 100 Hz, 53.01 kHz hsync */
+       { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,     0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 60 Hz, 53.5 kHz hsync */
+       { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 800x600 @ 85 Hz, 55.84 kHz hsync */
+       { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 70 Hz, 56.5 kHz hsync */
+       { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
+       { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
+               FB_VMODE_INTERLACED },
+
+       /* 800x600 @ 100 Hz, 64.02 kHz hsync */
+       { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 76 Hz, 62.5 kHz hsync */
+       { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 70 Hz, 62.4 kHz hsync */
+       { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
+       { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1400x1050 @ 60Hz, 63.9 kHz hsync */
+       { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
+       { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
+       { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 85 Hz, 70.24 kHz hsync */
+       { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 78 Hz, 70.8 kHz hsync */
+       { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
+       { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1600x1200 @ 60Hz, 75.00 kHz hsync */
+       { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 84 Hz, 76.0 kHz hsync */
+       { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
+       { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1024x768 @ 100Hz, 80.21 kHz hsync */
+       { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
+       { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
+       { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x864 @ 100 Hz, 89.62 kHz hsync */
+       { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
+       { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
+       { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
+       { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
+       { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
+       { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1800x1440 @ 64Hz, 96.15 kHz hsync  */
+       { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1800x1440 @ 70Hz, 104.52 kHz hsync  */
+       { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 512x384 @ 78 Hz, 31.50 kHz hsync */
+       { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 512x384 @ 85 Hz, 34.38 kHz hsync */
+       { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
+       { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
+       { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 320x240 @ 72 Hz, 36.5 kHz hsync */
+       { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
+       { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 400x300 @ 60 Hz, 37.8 kHz hsync */
+       { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 400x300 @ 72 Hz, 48.0 kHz hsync */
+       { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,     0,
+               FB_VMODE_DOUBLE },
+
+       /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
+       { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 480x300 @ 60 Hz, 37.8 kHz hsync */
+       { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 480x300 @ 63 Hz, 39.6 kHz hsync */
+       { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 480x300 @ 72 Hz, 48.0 kHz hsync */
+       { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0,
+               FB_VMODE_DOUBLE },
+
+       /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */
+       { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
+       { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
+       { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
+       { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0,
+               FB_VMODE_NONINTERLACED },
+
+       /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+       { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0,
+               FB_VMODE_INTERLACED },
+
+       /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+       { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0,
+               FB_VMODE_INTERLACED },
+
+       /* 864x480 @ 60 Hz, 35.15 kHz hsync */
+       { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0,
+               0, FB_VMODE_NONINTERLACED },
+};
+
+#ifdef CONFIG_FB_MODE_HELPERS
+const struct fb_videomode cea_modes[64] = {
+       /* #1: 640x480p@59.94/60Hz */
+       [1] = {
+               NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #3: 720x480p@59.94/60Hz */
+       [3] = {
+               NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #5: 1920x1080i@59.94/60Hz */
+       [5] = {
+               NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_INTERLACED, 0,
+       },
+       /* #7: 720(1440)x480iH@59.94/60Hz */
+       [7] = {
+               NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+               FB_VMODE_INTERLACED, 0,
+       },
+       /* #9: 720(1440)x240pH@59.94/60Hz */
+       [9] = {
+               NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #18: 720x576pH@50Hz */
+       [18] = {
+               NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #19: 1280x720p@50Hz */
+       [19] = {
+               NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #20: 1920x1080i@50Hz */
+       [20] = {
+               NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_INTERLACED, 0,
+       },
+       /* #32: 1920x1080p@23.98/24Hz */
+       [32] = {
+               NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
+               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+       /* #35: (2880)x480p4x@59.94/60Hz */
+       [35] = {
+               NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
+               FB_VMODE_NONINTERLACED, 0,
+       },
+};
+
+const struct fb_videomode vesa_modes[] = {
+       /* 0 640x350-85 VESA */
+       { NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
+         FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
+       /* 1 640x400-85 VESA */
+       { NULL, 85, 640, 400, 31746,  96, 32, 41, 01, 64, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 2 720x400-85 VESA */
+       { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 3 640x480-60 VESA */
+       { NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 4 640x480-72 VESA */
+       { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 5 640x480-75 VESA */
+       { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 6 640x480-85 VESA */
+       { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 7 800x600-56 VESA */
+       { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 8 800x600-60 VESA */
+       { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 9 800x600-72 VESA */
+       { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 10 800x600-75 VESA */
+       { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 11 800x600-85 VESA */
+       { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+        /* 12 1024x768i-43 VESA */
+       { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
+       /* 13 1024x768-60 VESA */
+       { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 14 1024x768-70 VESA */
+       { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 15 1024x768-75 VESA */
+       { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 16 1024x768-85 VESA */
+       { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 17 1152x864-75 VESA */
+       { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 18 1280x960-60 VESA */
+       { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 19 1280x960-85 VESA */
+       { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 20 1280x1024-60 VESA */
+       { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 21 1280x1024-75 VESA */
+       { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 22 1280x1024-85 VESA */
+       { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 23 1600x1200-60 VESA */
+       { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 24 1600x1200-65 VESA */
+       { NULL, 65, 1600, 1200, 5698, 304,  64, 46, 1, 192, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 25 1600x1200-70 VESA */
+       { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 26 1600x1200-75 VESA */
+       { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 27 1600x1200-85 VESA */
+       { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 28 1792x1344-60 VESA */
+       { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 29 1792x1344-75 VESA */
+       { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 30 1856x1392-60 VESA */
+       { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 31 1856x1392-75 VESA */
+       { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 32 1920x1440-60 VESA */
+       { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+       /* 33 1920x1440-75 VESA */
+       { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+};
+EXPORT_SYMBOL(vesa_modes);
+#endif /* CONFIG_FB_MODE_HELPERS */
+
+/**
+ *     fb_try_mode - test a video mode
+ *     @var: frame buffer user defined part of display
+ *     @info: frame buffer info structure
+ *     @mode: frame buffer video mode structure
+ *     @bpp: color depth in bits per pixel
+ *
+ *     Tries a video mode to test it's validity for device @info.
+ *
+ *     Returns 1 on success.
+ *
+ */
+
+static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+                      const struct fb_videomode *mode, unsigned int bpp)
+{
+       int err = 0;
+
+       DPRINTK("Trying mode %s %dx%d-%d@%d\n",
+               mode->name ? mode->name : "noname",
+               mode->xres, mode->yres, bpp, mode->refresh);
+       var->xres = mode->xres;
+       var->yres = mode->yres;
+       var->xres_virtual = mode->xres;
+       var->yres_virtual = mode->yres;
+       var->xoffset = 0;
+       var->yoffset = 0;
+       var->bits_per_pixel = bpp;
+       var->activate |= FB_ACTIVATE_TEST;
+       var->pixclock = mode->pixclock;
+       var->left_margin = mode->left_margin;
+       var->right_margin = mode->right_margin;
+       var->upper_margin = mode->upper_margin;
+       var->lower_margin = mode->lower_margin;
+       var->hsync_len = mode->hsync_len;
+       var->vsync_len = mode->vsync_len;
+       var->sync = mode->sync;
+       var->vmode = mode->vmode;
+       if (info->fbops->fb_check_var)
+               err = info->fbops->fb_check_var(var, info);
+       var->activate &= ~FB_ACTIVATE_TEST;
+       return err;
+}
+
+/**
+ *     fb_find_mode - finds a valid video mode
+ *     @var: frame buffer user defined part of display
+ *     @info: frame buffer info structure
+ *     @mode_option: string video mode to find
+ *     @db: video mode database
+ *     @dbsize: size of @db
+ *     @default_mode: default video mode to fall back to
+ *     @default_bpp: default color depth in bits per pixel
+ *
+ *     Finds a suitable video mode, starting with the specified mode
+ *     in @mode_option with fallback to @default_mode.  If
+ *     @default_mode fails, all modes in the video mode database will
+ *     be tried.
+ *
+ *     Valid mode specifiers for @mode_option:
+ *
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
+ *     <name>[-<bpp>][@<refresh>]
+ *
+ *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ *     <name> a string.
+ *
+ *      If 'M' is present after yres (and before refresh/bpp if present),
+ *      the function will compute the timings using VESA(tm) Coordinated
+ *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
+ *      reduced blanking (for flatpanels).  If 'i' is present, compute
+ *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
+ *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
+ *      'i' and 'm' must be after 'M' and 'R'. Example:
+ *
+ *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
+ *
+ *     NOTE: The passed struct @var is _not_ cleared!  This allows you
+ *     to supply values for e.g. the grayscale and accel_flags fields.
+ *
+ *     Returns zero for failure, 1 if using specified @mode_option,
+ *     2 if using specified @mode_option with an ignored refresh rate,
+ *     3 if default mode is used, 4 if fall back to any valid mode.
+ *
+ */
+
+int fb_find_mode(struct fb_var_screeninfo *var,
+                struct fb_info *info, const char *mode_option,
+                const struct fb_videomode *db, unsigned int dbsize,
+                const struct fb_videomode *default_mode,
+                unsigned int default_bpp)
+{
+       int i;
+
+       /* Set up defaults */
+       if (!db) {
+               db = modedb;
+               dbsize = ARRAY_SIZE(modedb);
+       }
+
+       if (!default_mode)
+               default_mode = &db[0];
+
+       if (!default_bpp)
+               default_bpp = 8;
+
+       /* Did the user specify a video mode? */
+       if (!mode_option)
+               mode_option = fb_mode_option;
+       if (mode_option) {
+               const char *name = mode_option;
+               unsigned int namelen = strlen(name);
+               int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+               unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
+               int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+               int margins = 0;
+               u32 best, diff, tdiff;
+
+               for (i = namelen-1; i >= 0; i--) {
+                       switch (name[i]) {
+                       case '@':
+                               namelen = i;
+                               if (!refresh_specified && !bpp_specified &&
+                                   !yres_specified) {
+                                       refresh = simple_strtol(&name[i+1], NULL,
+                                                               10);
+                                       refresh_specified = 1;
+                                       if (cvt || rb)
+                                               cvt = 0;
+                               } else
+                                       goto done;
+                               break;
+                       case '-':
+                               namelen = i;
+                               if (!bpp_specified && !yres_specified) {
+                                       bpp = simple_strtol(&name[i+1], NULL,
+                                                           10);
+                                       bpp_specified = 1;
+                                       if (cvt || rb)
+                                               cvt = 0;
+                               } else
+                                       goto done;
+                               break;
+                       case 'x':
+                               if (!yres_specified) {
+                                       yres = simple_strtol(&name[i+1], NULL,
+                                                            10);
+                                       yres_specified = 1;
+                               } else
+                                       goto done;
+                               break;
+                       case '0' ... '9':
+                               break;
+                       case 'M':
+                               if (!yres_specified)
+                                       cvt = 1;
+                               break;
+                       case 'R':
+                               if (!cvt)
+                                       rb = 1;
+                               break;
+                       case 'm':
+                               if (!cvt)
+                                       margins = 1;
+                               break;
+                       case 'i':
+                               if (!cvt)
+                                       interlace = 1;
+                               break;
+                       default:
+                               goto done;
+                       }
+               }
+               if (i < 0 && yres_specified) {
+                       xres = simple_strtol(name, NULL, 10);
+                       res_specified = 1;
+               }
+done:
+               if (cvt) {
+                       struct fb_videomode cvt_mode;
+                       int ret;
+
+                       DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
+                               (refresh) ? refresh : 60,
+                               (rb) ? " reduced blanking" : "",
+                               (margins) ? " with margins" : "",
+                               (interlace) ? " interlaced" : "");
+
+                       memset(&cvt_mode, 0, sizeof(cvt_mode));
+                       cvt_mode.xres = xres;
+                       cvt_mode.yres = yres;
+                       cvt_mode.refresh = (refresh) ? refresh : 60;
+
+                       if (interlace)
+                               cvt_mode.vmode |= FB_VMODE_INTERLACED;
+                       else
+                               cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
+
+                       ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
+
+                       if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
+                               DPRINTK("modedb CVT: CVT mode ok\n");
+                               return 1;
+                       }
+
+                       DPRINTK("CVT mode invalid, getting mode from database\n");
+               }
+
+               DPRINTK("Trying specified video mode%s %ix%i\n",
+                       refresh_specified ? "" : " (ignoring refresh rate)",
+                       xres, yres);
+
+               if (!refresh_specified) {
+                       /*
+                        * If the caller has provided a custom mode database and
+                        * a valid monspecs structure, we look for the mode with
+                        * the highest refresh rate.  Otherwise we play it safe
+                        * it and try to find a mode with a refresh rate closest
+                        * to the standard 60 Hz.
+                        */
+                       if (db != modedb &&
+                           info->monspecs.vfmin && info->monspecs.vfmax &&
+                           info->monspecs.hfmin && info->monspecs.hfmax &&
+                           info->monspecs.dclkmax) {
+                               refresh = 1000;
+                       } else {
+                               refresh = 60;
+                       }
+               }
+
+               diff = -1;
+               best = -1;
+               for (i = 0; i < dbsize; i++) {
+                       if ((name_matches(db[i], name, namelen) ||
+                            (res_specified && res_matches(db[i], xres, yres))) &&
+                           !fb_try_mode(var, info, &db[i], bpp)) {
+                               if (refresh_specified && db[i].refresh == refresh)
+                                       return 1;
+
+                               if (abs(db[i].refresh - refresh) < diff) {
+                                       diff = abs(db[i].refresh - refresh);
+                                       best = i;
+                               }
+                       }
+               }
+               if (best != -1) {
+                       fb_try_mode(var, info, &db[best], bpp);
+                       return (refresh_specified) ? 2 : 1;
+               }
+
+               diff = 2 * (xres + yres);
+               best = -1;
+               DPRINTK("Trying best-fit modes\n");
+               for (i = 0; i < dbsize; i++) {
+                       DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
+                       if (!fb_try_mode(var, info, &db[i], bpp)) {
+                               tdiff = abs(db[i].xres - xres) +
+                                       abs(db[i].yres - yres);
+
+                               /*
+                                * Penalize modes with resolutions smaller
+                                * than requested.
+                                */
+                               if (xres > db[i].xres || yres > db[i].yres)
+                                       tdiff += xres + yres;
+
+                               if (diff > tdiff) {
+                                       diff = tdiff;
+                                       best = i;
+                               }
+                       }
+               }
+               if (best != -1) {
+                       fb_try_mode(var, info, &db[best], bpp);
+                       return 5;
+               }
+       }
+
+       DPRINTK("Trying default video mode\n");
+       if (!fb_try_mode(var, info, default_mode, default_bpp))
+               return 3;
+
+       DPRINTK("Trying all modes\n");
+       for (i = 0; i < dbsize; i++)
+               if (!fb_try_mode(var, info, &db[i], default_bpp))
+                       return 4;
+
+       DPRINTK("No valid mode found\n");
+       return 0;
+}
+
+/**
+ * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode
+ * @mode: pointer to struct fb_videomode
+ * @var: pointer to struct fb_var_screeninfo
+ */
+void fb_var_to_videomode(struct fb_videomode *mode,
+                        const struct fb_var_screeninfo *var)
+{
+       u32 pixclock, hfreq, htotal, vtotal;
+
+       mode->name = NULL;
+       mode->xres = var->xres;
+       mode->yres = var->yres;
+       mode->pixclock = var->pixclock;
+       mode->hsync_len = var->hsync_len;
+       mode->vsync_len = var->vsync_len;
+       mode->left_margin = var->left_margin;
+       mode->right_margin = var->right_margin;
+       mode->upper_margin = var->upper_margin;
+       mode->lower_margin = var->lower_margin;
+       mode->sync = var->sync;
+       mode->vmode = var->vmode & FB_VMODE_MASK;
+       mode->flag = FB_MODE_IS_FROM_VAR;
+       mode->refresh = 0;
+
+       if (!var->pixclock)
+               return;
+
+       pixclock = PICOS2KHZ(var->pixclock) * 1000;
+
+       htotal = var->xres + var->right_margin + var->hsync_len +
+               var->left_margin;
+       vtotal = var->yres + var->lower_margin + var->vsync_len +
+               var->upper_margin;
+
+       if (var->vmode & FB_VMODE_INTERLACED)
+               vtotal /= 2;
+       if (var->vmode & FB_VMODE_DOUBLE)
+               vtotal *= 2;
+
+       hfreq = pixclock/htotal;
+       mode->refresh = hfreq/vtotal;
+}
+
+/**
+ * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo
+ * @var: pointer to struct fb_var_screeninfo
+ * @mode: pointer to struct fb_videomode
+ */
+void fb_videomode_to_var(struct fb_var_screeninfo *var,
+                        const struct fb_videomode *mode)
+{
+       var->xres = mode->xres;
+       var->yres = mode->yres;
+       var->xres_virtual = mode->xres;
+       var->yres_virtual = mode->yres;
+       var->xoffset = 0;
+       var->yoffset = 0;
+       var->pixclock = mode->pixclock;
+       var->left_margin = mode->left_margin;
+       var->right_margin = mode->right_margin;
+       var->upper_margin = mode->upper_margin;
+       var->lower_margin = mode->lower_margin;
+       var->hsync_len = mode->hsync_len;
+       var->vsync_len = mode->vsync_len;
+       var->sync = mode->sync;
+       var->vmode = mode->vmode & FB_VMODE_MASK;
+}
+
+/**
+ * fb_mode_is_equal - compare 2 videomodes
+ * @mode1: first videomode
+ * @mode2: second videomode
+ *
+ * RETURNS:
+ * 1 if equal, 0 if not
+ */
+int fb_mode_is_equal(const struct fb_videomode *mode1,
+                    const struct fb_videomode *mode2)
+{
+       return (mode1->xres         == mode2->xres &&
+               mode1->yres         == mode2->yres &&
+               mode1->pixclock     == mode2->pixclock &&
+               mode1->hsync_len    == mode2->hsync_len &&
+               mode1->vsync_len    == mode2->vsync_len &&
+               mode1->left_margin  == mode2->left_margin &&
+               mode1->right_margin == mode2->right_margin &&
+               mode1->upper_margin == mode2->upper_margin &&
+               mode1->lower_margin == mode2->lower_margin &&
+               mode1->sync         == mode2->sync &&
+               mode1->vmode        == mode2->vmode);
+}
+
+/**
+ * fb_find_best_mode - find best matching videomode
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to struct list_head of modelist
+ *
+ * RETURNS:
+ * struct fb_videomode, NULL if none found
+ *
+ * IMPORTANT:
+ * This function assumes that all modelist entries in
+ * info->modelist are valid.
+ *
+ * NOTES:
+ * Finds best matching videomode which has an equal or greater dimension than
+ * var->xres and var->yres.  If more than 1 videomode is found, will return
+ * the videomode with the highest refresh rate
+ */
+const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var,
+                                            struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       struct fb_videomode *mode, *best = NULL;
+       u32 diff = -1;
+
+       list_for_each(pos, head) {
+               u32 d;
+
+               modelist = list_entry(pos, struct fb_modelist, list);
+               mode = &modelist->mode;
+
+               if (mode->xres >= var->xres && mode->yres >= var->yres) {
+                       d = (mode->xres - var->xres) +
+                               (mode->yres - var->yres);
+                       if (diff > d) {
+                               diff = d;
+                               best = mode;
+                       } else if (diff == d && best &&
+                                  mode->refresh > best->refresh)
+                               best = mode;
+               }
+       }
+       return best;
+}
+
+/**
+ * fb_find_nearest_mode - find closest videomode
+ *
+ * @mode: pointer to struct fb_videomode
+ * @head: pointer to modelist
+ *
+ * Finds best matching videomode, smaller or greater in dimension.
+ * If more than 1 videomode is found, will return the videomode with
+ * the closest refresh rate.
+ */
+const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode,
+                                               struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       struct fb_videomode *cmode, *best = NULL;
+       u32 diff = -1, diff_refresh = -1;
+
+       list_for_each(pos, head) {
+               u32 d;
+
+               modelist = list_entry(pos, struct fb_modelist, list);
+               cmode = &modelist->mode;
+
+               d = abs(cmode->xres - mode->xres) +
+                       abs(cmode->yres - mode->yres);
+               if (diff > d) {
+                       diff = d;
+                       diff_refresh = abs(cmode->refresh - mode->refresh);
+                       best = cmode;
+               } else if (diff == d) {
+                       d = abs(cmode->refresh - mode->refresh);
+                       if (diff_refresh > d) {
+                               diff_refresh = d;
+                               best = cmode;
+                       }
+               }
+       }
+
+       return best;
+}
+
+/**
+ * fb_match_mode - find a videomode which exactly matches the timings in var
+ * @var: pointer to struct fb_var_screeninfo
+ * @head: pointer to struct list_head of modelist
+ *
+ * RETURNS:
+ * struct fb_videomode, NULL if none found
+ */
+const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
+                                        struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       struct fb_videomode *m, mode;
+
+       fb_var_to_videomode(&mode, var);
+       list_for_each(pos, head) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+               if (fb_mode_is_equal(m, &mode))
+                       return m;
+       }
+       return NULL;
+}
+
+/**
+ * fb_add_videomode - adds videomode entry to modelist
+ * @mode: videomode to add
+ * @head: struct list_head of modelist
+ *
+ * NOTES:
+ * Will only add unmatched mode entries
+ */
+int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       struct fb_videomode *m;
+       int found = 0;
+
+       list_for_each(pos, head) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+               if (fb_mode_is_equal(m, mode)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               modelist = kmalloc(sizeof(struct fb_modelist),
+                                                 GFP_KERNEL);
+
+               if (!modelist)
+                       return -ENOMEM;
+               modelist->mode = *mode;
+               list_add(&modelist->list, head);
+       }
+       return 0;
+}
+
+/**
+ * fb_delete_videomode - removed videomode entry from modelist
+ * @mode: videomode to remove
+ * @head: struct list_head of modelist
+ *
+ * NOTES:
+ * Will remove all matching mode entries
+ */
+void fb_delete_videomode(const struct fb_videomode *mode,
+                        struct list_head *head)
+{
+       struct list_head *pos, *n;
+       struct fb_modelist *modelist;
+       struct fb_videomode *m;
+
+       list_for_each_safe(pos, n, head) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+               if (fb_mode_is_equal(m, mode)) {
+                       list_del(pos);
+                       kfree(pos);
+               }
+       }
+}
+
+/**
+ * fb_destroy_modelist - destroy modelist
+ * @head: struct list_head of modelist
+ */
+void fb_destroy_modelist(struct list_head *head)
+{
+       struct list_head *pos, *n;
+
+       list_for_each_safe(pos, n, head) {
+               list_del(pos);
+               kfree(pos);
+       }
+}
+EXPORT_SYMBOL_GPL(fb_destroy_modelist);
+
+/**
+ * fb_videomode_to_modelist - convert mode array to mode list
+ * @modedb: array of struct fb_videomode
+ * @num: number of entries in array
+ * @head: struct list_head of modelist
+ */
+void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num,
+                             struct list_head *head)
+{
+       int i;
+
+       INIT_LIST_HEAD(head);
+
+       for (i = 0; i < num; i++) {
+               if (fb_add_videomode(&modedb[i], head))
+                       return;
+       }
+}
+
+const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs,
+                                               struct list_head *head)
+{
+       struct list_head *pos;
+       struct fb_modelist *modelist;
+       const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
+       int first = 0;
+
+       if (!head->prev || !head->next || list_empty(head))
+               goto finished;
+
+       /* get the first detailed mode and the very first mode */
+       list_for_each(pos, head) {
+               modelist = list_entry(pos, struct fb_modelist, list);
+               m = &modelist->mode;
+
+               if (!first) {
+                       m1 = m;
+                       first = 1;
+               }
+
+               if (m->flag & FB_MODE_IS_FIRST) {
+                       md = m;
+                       break;
+               }
+       }
+
+       /* first detailed timing is preferred */
+       if (specs->misc & FB_MISC_1ST_DETAIL) {
+               best = md;
+               goto finished;
+       }
+
+       /* find best mode based on display width and height */
+       if (specs->max_x && specs->max_y) {
+               struct fb_var_screeninfo var;
+
+               memset(&var, 0, sizeof(struct fb_var_screeninfo));
+               var.xres = (specs->max_x * 7200)/254;
+               var.yres = (specs->max_y * 7200)/254;
+               m = fb_find_best_mode(&var, head);
+               if (m) {
+                       best = m;
+                       goto finished;
+               }
+       }
+
+       /* use first detailed mode */
+       if (md) {
+               best = md;
+               goto finished;
+       }
+
+       /* last resort, use the very first mode */
+       best = m1;
+finished:
+       return best;
+}
+EXPORT_SYMBOL(fb_find_best_display);
+
+EXPORT_SYMBOL(fb_videomode_to_var);
+EXPORT_SYMBOL(fb_var_to_videomode);
+EXPORT_SYMBOL(fb_mode_is_equal);
+EXPORT_SYMBOL(fb_add_videomode);
+EXPORT_SYMBOL(fb_match_mode);
+EXPORT_SYMBOL(fb_find_best_mode);
+EXPORT_SYMBOL(fb_find_nearest_mode);
+EXPORT_SYMBOL(fb_videomode_to_modelist);
+EXPORT_SYMBOL(fb_find_mode);
+EXPORT_SYMBOL(fb_find_mode_cvt);
diff --git a/drivers/video/fbdev/core/svgalib.c b/drivers/video/fbdev/core/svgalib.c
new file mode 100644 (file)
index 0000000..9e01322
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Common utility functions for VGA-based graphics cards.
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * 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.
+ *
+ * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+
+/* Write a CRT register value spread across multiple registers */
+void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
+{
+       u8 regval, bitval, bitnum;
+
+       while (regset->regnum != VGA_REGSET_END_VAL) {
+               regval = vga_rcrt(regbase, regset->regnum);
+               bitnum = regset->lowbit;
+               while (bitnum <= regset->highbit) {
+                       bitval = 1 << bitnum;
+                       regval = regval & ~bitval;
+                       if (value & 1) regval = regval | bitval;
+                       bitnum ++;
+                       value = value >> 1;
+               }
+               vga_wcrt(regbase, regset->regnum, regval);
+               regset ++;
+       }
+}
+
+/* Write a sequencer register value spread across multiple registers */
+void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
+{
+       u8 regval, bitval, bitnum;
+
+       while (regset->regnum != VGA_REGSET_END_VAL) {
+               regval = vga_rseq(regbase, regset->regnum);
+               bitnum = regset->lowbit;
+               while (bitnum <= regset->highbit) {
+                       bitval = 1 << bitnum;
+                       regval = regval & ~bitval;
+                       if (value & 1) regval = regval | bitval;
+                       bitnum ++;
+                       value = value >> 1;
+               }
+               vga_wseq(regbase, regset->regnum, regval);
+               regset ++;
+       }
+}
+
+static unsigned int svga_regset_size(const struct vga_regset *regset)
+{
+       u8 count = 0;
+
+       while (regset->regnum != VGA_REGSET_END_VAL) {
+               count += regset->highbit - regset->lowbit + 1;
+               regset ++;
+       }
+       return 1 << count;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Set graphics controller registers to sane values */
+void svga_set_default_gfx_regs(void __iomem *regbase)
+{
+       /* All standard GFX registers (GR00 - GR08) */
+       vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00);
+       vga_wgfx(regbase, VGA_GFX_MODE, 0x00);
+/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */
+/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */
+       vga_wgfx(regbase, VGA_GFX_MISC, 0x05);
+/*     vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */
+       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F);
+       vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF);
+}
+
+/* Set attribute controller registers to sane values */
+void svga_set_default_atc_regs(void __iomem *regbase)
+{
+       u8 count;
+
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x00);
+
+       /* All standard ATC registers (AR00 - AR14) */
+       for (count = 0; count <= 0xF; count ++)
+               svga_wattr(regbase, count, count);
+
+       svga_wattr(regbase, VGA_ATC_MODE, 0x01);
+/*     svga_wattr(regbase, VGA_ATC_MODE, 0x41); */
+       svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00);
+       svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F);
+       svga_wattr(regbase, VGA_ATC_PEL, 0x00);
+       svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00);
+
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x20);
+}
+
+/* Set sequencer registers to sane values */
+void svga_set_default_seq_regs(void __iomem *regbase)
+{
+       /* Standard sequencer registers (SR01 - SR04), SR00 is not set */
+       vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
+       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
+       vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
+/*     vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
+       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
+}
+
+/* Set CRTC registers to sane values */
+void svga_set_default_crt_regs(void __iomem *regbase)
+{
+       /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
+       svga_wcrt_mask(regbase, 0x03, 0x80, 0x80);      /* Enable vertical retrace EVRA */
+       vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
+       svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F);
+       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
+       vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3);
+}
+
+void svga_set_textmode_vga_regs(void __iomem *regbase)
+{
+       /* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */
+       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);
+       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03);
+
+       vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */
+       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f);
+       svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f);
+
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00);
+
+       vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */
+       vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */
+       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00);
+
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x00);
+
+       svga_wattr(regbase, 0x10, 0x0C);                        /* Attribute Mode Control Register - text mode, blinking and line graphics */
+       svga_wattr(regbase, 0x13, 0x08);                        /* Horizontal Pixel Panning Register  */
+
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x20);
+}
+
+#if 0
+void svga_dump_var(struct fb_var_screeninfo *var, int node)
+{
+       pr_debug("fb%d: var.vmode         : 0x%X\n", node, var->vmode);
+       pr_debug("fb%d: var.xres          : %d\n", node, var->xres);
+       pr_debug("fb%d: var.yres          : %d\n", node, var->yres);
+       pr_debug("fb%d: var.bits_per_pixel: %d\n", node, var->bits_per_pixel);
+       pr_debug("fb%d: var.xres_virtual  : %d\n", node, var->xres_virtual);
+       pr_debug("fb%d: var.yres_virtual  : %d\n", node, var->yres_virtual);
+       pr_debug("fb%d: var.left_margin   : %d\n", node, var->left_margin);
+       pr_debug("fb%d: var.right_margin  : %d\n", node, var->right_margin);
+       pr_debug("fb%d: var.upper_margin  : %d\n", node, var->upper_margin);
+       pr_debug("fb%d: var.lower_margin  : %d\n", node, var->lower_margin);
+       pr_debug("fb%d: var.hsync_len     : %d\n", node, var->hsync_len);
+       pr_debug("fb%d: var.vsync_len     : %d\n", node, var->vsync_len);
+       pr_debug("fb%d: var.sync          : 0x%X\n", node, var->sync);
+       pr_debug("fb%d: var.pixclock      : %d\n\n", node, var->pixclock);
+}
+#endif  /*  0  */
+
+
+/* ------------------------------------------------------------------------- */
+
+
+void svga_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+       const u8 *font = map->data;
+       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+       int i, c;
+
+       if ((map->width != 8) || (map->height != 16) ||
+           (map->depth != 1) || (map->length != 256)) {
+               fb_err(info, "unsupported font parameters: width %d, height %d, depth %d, length %d\n",
+                      map->width, map->height, map->depth, map->length);
+               return;
+       }
+
+       fb += 2;
+       for (c = 0; c < map->length; c++) {
+               for (i = 0; i < map->height; i++) {
+                       fb_writeb(font[i], fb + i * 4);
+//                     fb[i * 4] = font[i];
+               }
+               fb += 128;
+               font += map->height;
+       }
+}
+
+/* Copy area in text (tileblit) mode */
+void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
+{
+       int dx, dy;
+       /*  colstride is halved in this function because u16 are used */
+       int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+       int rowstride = colstride * (info->var.xres_virtual / 8);
+       u16 __iomem *fb = (u16 __iomem *) info->screen_base;
+       u16 __iomem *src, *dst;
+
+       if ((area->sy > area->dy) ||
+           ((area->sy == area->dy) && (area->sx > area->dx))) {
+               src = fb + area->sx * colstride + area->sy * rowstride;
+               dst = fb + area->dx * colstride + area->dy * rowstride;
+           } else {
+               src = fb + (area->sx + area->width - 1) * colstride
+                        + (area->sy + area->height - 1) * rowstride;
+               dst = fb + (area->dx + area->width - 1) * colstride
+                        + (area->dy + area->height - 1) * rowstride;
+
+               colstride = -colstride;
+               rowstride = -rowstride;
+           }
+
+       for (dy = 0; dy < area->height; dy++) {
+               u16 __iomem *src2 = src;
+               u16 __iomem *dst2 = dst;
+               for (dx = 0; dx < area->width; dx++) {
+                       fb_writew(fb_readw(src2), dst2);
+//                     *dst2 = *src2;
+                       src2 += colstride;
+                       dst2 += colstride;
+               }
+               src += rowstride;
+               dst += rowstride;
+       }
+}
+
+/* Fill area in text (tileblit) mode */
+void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)
+{
+       int dx, dy;
+       int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+       int rowstride = colstride * (info->var.xres_virtual / 8);
+       int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
+       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+       fb += rect->sx * colstride + rect->sy * rowstride;
+
+       for (dy = 0; dy < rect->height; dy++) {
+               u8 __iomem *fb2 = fb;
+               for (dx = 0; dx < rect->width; dx++) {
+                       fb_writeb(rect->index, fb2);
+                       fb_writeb(attr, fb2 + 1);
+                       fb2 += colstride;
+               }
+               fb += rowstride;
+       }
+}
+
+/* Write text in text (tileblit) mode */
+void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
+{
+       int dx, dy, i;
+       int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+       int rowstride = colstride * (info->var.xres_virtual / 8);
+       int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
+       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+       fb += blit->sx * colstride + blit->sy * rowstride;
+
+       i=0;
+       for (dy=0; dy < blit->height; dy ++) {
+               u8 __iomem *fb2 = fb;
+               for (dx = 0; dx < blit->width; dx ++) {
+                       fb_writeb(blit->indices[i], fb2);
+                       fb_writeb(attr, fb2 + 1);
+                       fb2 += colstride;
+                       i ++;
+                       if (i == blit->length) return;
+               }
+               fb += rowstride;
+       }
+
+}
+
+/* Set cursor in text (tileblit) mode */
+void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor)
+{
+       u8 cs = 0x0d;
+       u8 ce = 0x0e;
+       u16 pos =  cursor->sx + (info->var.xoffset /  8)
+               + (cursor->sy + (info->var.yoffset / 16))
+                  * (info->var.xres_virtual / 8);
+
+       if (! cursor -> mode)
+               return;
+
+       svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */
+
+       if (cursor -> shape == FB_TILE_CURSOR_NONE)
+               return;
+
+       switch (cursor -> shape) {
+       case FB_TILE_CURSOR_UNDERLINE:
+               cs = 0x0d;
+               break;
+       case FB_TILE_CURSOR_LOWER_THIRD:
+               cs = 0x09;
+               break;
+       case FB_TILE_CURSOR_LOWER_HALF:
+               cs = 0x07;
+               break;
+       case FB_TILE_CURSOR_TWO_THIRDS:
+               cs = 0x05;
+               break;
+       case FB_TILE_CURSOR_BLOCK:
+               cs = 0x01;
+               break;
+       }
+
+       /* set cursor position */
+       vga_wcrt(regbase, 0x0E, pos >> 8);
+       vga_wcrt(regbase, 0x0F, pos & 0xFF);
+
+       vga_wcrt(regbase, 0x0B, ce); /* set cursor end */
+       vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */
+}
+
+int svga_get_tilemax(struct fb_info *info)
+{
+       return 256;
+}
+
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+                  struct fb_var_screeninfo *var)
+{
+       if (var->bits_per_pixel == 0) {
+               /* can only support 256 8x16 bitmap */
+               caps->x = 1 << (8 - 1);
+               caps->y = 1 << (16 - 1);
+               caps->len = 256;
+       } else {
+               caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+               caps->y = ~(u32)0;
+               caps->len = ~(u32)0;
+       }
+}
+EXPORT_SYMBOL(svga_get_caps);
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ *  Compute PLL settings (M, N, R)
+ *  F_VCO = (F_BASE * M) / N
+ *  F_OUT = F_VCO / (2^R)
+ */
+
+static inline u32 abs_diff(u32 a, u32 b)
+{
+       return (a > b) ? (a - b) : (b - a);
+}
+
+int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)
+{
+       u16 am, an, ar;
+       u32 f_vco, f_current, delta_current, delta_best;
+
+       pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);
+
+       ar = pll->r_max;
+       f_vco = f_wanted << ar;
+
+       /* overflow check */
+       if ((f_vco >> ar) != f_wanted)
+               return -EINVAL;
+
+       /* It is usually better to have greater VCO clock
+          because of better frequency stability.
+          So first try r_max, then r smaller. */
+       while ((ar > pll->r_min) && (f_vco > pll->f_vco_max)) {
+               ar--;
+               f_vco = f_vco >> 1;
+       }
+
+       /* VCO bounds check */
+       if ((f_vco < pll->f_vco_min) || (f_vco > pll->f_vco_max))
+               return -EINVAL;
+
+       delta_best = 0xFFFFFFFF;
+       *m = 0;
+       *n = 0;
+       *r = ar;
+
+       am = pll->m_min;
+       an = pll->n_min;
+
+       while ((am <= pll->m_max) && (an <= pll->n_max)) {
+               f_current = (pll->f_base * am) / an;
+               delta_current = abs_diff (f_current, f_vco);
+
+               if (delta_current < delta_best) {
+                       delta_best = delta_current;
+                       *m = am;
+                       *n = an;
+               }
+
+               if (f_current <= f_vco) {
+                       am ++;
+               } else {
+                       an ++;
+               }
+       }
+
+       f_current = (pll->f_base * *m) / *n;
+       pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);
+       pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Check CRT timing values */
+int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
+{
+       u32 value;
+
+       var->xres         = (var->xres+7)&~7;
+       var->left_margin  = (var->left_margin+7)&~7;
+       var->right_margin = (var->right_margin+7)&~7;
+       var->hsync_len    = (var->hsync_len+7)&~7;
+
+       /* Check horizontal total */
+       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+       if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))
+               return -EINVAL;
+
+       /* Check horizontal display and blank start */
+       value = var->xres;
+       if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))
+               return -EINVAL;
+       if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))
+               return -EINVAL;
+
+       /* Check horizontal sync start */
+       value = var->xres + var->right_margin;
+       if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))
+               return -EINVAL;
+
+       /* Check horizontal blank end (or length) */
+       value = var->left_margin + var->right_margin + var->hsync_len;
+       if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))
+               return -EINVAL;
+
+       /* Check horizontal sync end (or length) */
+       value = var->hsync_len;
+       if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))
+               return -EINVAL;
+
+       /* Check vertical total */
+       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+       if ((value - 1) >= svga_regset_size(tm->v_total_regs))
+               return -EINVAL;
+
+       /* Check vertical display and blank start */
+       value = var->yres;
+       if ((value - 1) >= svga_regset_size(tm->v_display_regs))
+               return -EINVAL;
+       if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs))
+               return -EINVAL;
+
+       /* Check vertical sync start */
+       value = var->yres + var->lower_margin;
+       if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs))
+               return -EINVAL;
+
+       /* Check vertical blank end (or length) */
+       value = var->upper_margin + var->lower_margin + var->vsync_len;
+       if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))
+               return -EINVAL;
+
+       /* Check vertical sync end  (or length) */
+       value = var->vsync_len;
+       if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Set CRT timing registers */
+void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
+                     struct fb_var_screeninfo *var,
+                     u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
+{
+       u8 regval;
+       u32 value;
+
+       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal total      : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5);
+
+       value = var->xres;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal display    : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1);
+
+       value = var->xres;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal blank start: %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder);
+
+       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal blank end  : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder);
+
+       value = var->xres + var->right_margin;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal sync start : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8));
+
+       value = var->xres + var->right_margin + var->hsync_len;
+       value = (value * hmul) / hdiv;
+       pr_debug("fb%d: horizontal sync end   : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8));
+
+       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical total        : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_total_regs, value - 2);
+
+       value = var->yres;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical display      : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_display_regs, value - 1);
+
+       value = var->yres;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical blank start  : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_blank_start_regs, value);
+
+       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical blank end    : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2);
+
+       value = var->yres + var->lower_margin;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical sync start   : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_sync_start_regs, value);
+
+       value = var->yres + var->lower_margin + var->vsync_len;
+       value = (value * vmul) / vdiv;
+       pr_debug("fb%d: vertical sync end     : %d\n", node, value);
+       svga_wcrt_multi(regbase, tm->v_sync_end_regs, value);
+
+       /* Set horizontal and vertical sync pulse polarity in misc register */
+
+       regval = vga_r(regbase, VGA_MIS_R);
+       if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
+               pr_debug("fb%d: positive horizontal sync\n", node);
+               regval = regval & ~0x80;
+       } else {
+               pr_debug("fb%d: negative horizontal sync\n", node);
+               regval = regval | 0x80;
+       }
+       if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
+               pr_debug("fb%d: positive vertical sync\n", node);
+               regval = regval & ~0x40;
+       } else {
+               pr_debug("fb%d: negative vertical sync\n\n", node);
+               regval = regval | 0x40;
+       }
+       vga_w(regbase, VGA_MIS_W, regval);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static inline int match_format(const struct svga_fb_format *frm,
+                              struct fb_var_screeninfo *var)
+{
+       int i = 0;
+       int stored = -EINVAL;
+
+       while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
+       {
+               if ((var->bits_per_pixel == frm->bits_per_pixel) &&
+                   (var->red.length     <= frm->red.length)     &&
+                   (var->green.length   <= frm->green.length)   &&
+                   (var->blue.length    <= frm->blue.length)    &&
+                   (var->transp.length  <= frm->transp.length)  &&
+                   (var->nonstd         == frm->nonstd))
+                       return i;
+               if (var->bits_per_pixel == frm->bits_per_pixel)
+                       stored = i;
+               i++;
+               frm++;
+       }
+       return stored;
+}
+
+int svga_match_format(const struct svga_fb_format *frm,
+                     struct fb_var_screeninfo *var,
+                     struct fb_fix_screeninfo *fix)
+{
+       int i = match_format(frm, var);
+
+       if (i >= 0) {
+               var->bits_per_pixel = frm[i].bits_per_pixel;
+               var->red            = frm[i].red;
+               var->green          = frm[i].green;
+               var->blue           = frm[i].blue;
+               var->transp         = frm[i].transp;
+               var->nonstd         = frm[i].nonstd;
+               if (fix != NULL) {
+                       fix->type      = frm[i].type;
+                       fix->type_aux  = frm[i].type_aux;
+                       fix->visual    = frm[i].visual;
+                       fix->xpanstep  = frm[i].xpanstep;
+               }
+       }
+
+       return i;
+}
+
+
+EXPORT_SYMBOL(svga_wcrt_multi);
+EXPORT_SYMBOL(svga_wseq_multi);
+
+EXPORT_SYMBOL(svga_set_default_gfx_regs);
+EXPORT_SYMBOL(svga_set_default_atc_regs);
+EXPORT_SYMBOL(svga_set_default_seq_regs);
+EXPORT_SYMBOL(svga_set_default_crt_regs);
+EXPORT_SYMBOL(svga_set_textmode_vga_regs);
+
+EXPORT_SYMBOL(svga_settile);
+EXPORT_SYMBOL(svga_tilecopy);
+EXPORT_SYMBOL(svga_tilefill);
+EXPORT_SYMBOL(svga_tileblit);
+EXPORT_SYMBOL(svga_tilecursor);
+EXPORT_SYMBOL(svga_get_tilemax);
+
+EXPORT_SYMBOL(svga_compute_pll);
+EXPORT_SYMBOL(svga_check_timings);
+EXPORT_SYMBOL(svga_set_timings);
+EXPORT_SYMBOL(svga_match_format);
+
+MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_DESCRIPTION("Common utility functions for VGA-based graphics cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c
new file mode 100644 (file)
index 0000000..844a32f
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *  Generic Bit Block Transfer for frame buffers located in system RAM with
+ *  packed pixels of any depth.
+ *
+ *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
+ *  on Geert Uytterhoeven's copyarea routine)
+ *
+ *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "fb_draw.h"
+
+    /*
+     *  Generic bitwise copy algorithm
+     */
+
+static void
+bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
+               const unsigned long *src, int src_idx, int bits, unsigned n)
+{
+       unsigned long first, last;
+       int const shift = dst_idx-src_idx;
+       int left, right;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (!shift) {
+               /* Same alignment for source and dest */
+               if (dst_idx+n <= bits) {
+                       /* Single word */
+                       if (last)
+                               first &= last;
+                       *dst = comp(*src, *dst, first);
+               } else {
+                       /* Multiple destination words */
+                       /* Leading bits */
+                       if (first != ~0UL) {
+                               *dst = comp(*src, *dst, first);
+                               dst++;
+                               src++;
+                               n -= bits - dst_idx;
+                       }
+
+                       /* Main chunk */
+                       n /= bits;
+                       while (n >= 8) {
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               n -= 8;
+                       }
+                       while (n--)
+                               *dst++ = *src++;
+
+                       /* Trailing bits */
+                       if (last)
+                               *dst = comp(*src, *dst, last);
+               }
+       } else {
+               unsigned long d0, d1;
+               int m;
+
+               /* Different alignment for source and dest */
+               right = shift & (bits - 1);
+               left = -shift & (bits - 1);
+
+               if (dst_idx+n <= bits) {
+                       /* Single destination word */
+                       if (last)
+                               first &= last;
+                       if (shift > 0) {
+                               /* Single source word */
+                               *dst = comp(*src >> right, *dst, first);
+                       } else if (src_idx+n <= bits) {
+                               /* Single source word */
+                               *dst = comp(*src << left, *dst, first);
+                       } else {
+                               /* 2 source words */
+                               d0 = *src++;
+                               d1 = *src;
+                               *dst = comp(d0 << left | d1 >> right, *dst,
+                                           first);
+                       }
+               } else {
+                       /* Multiple destination words */
+                       /** We must always remember the last value read,
+                           because in case SRC and DST overlap bitwise (e.g.
+                           when moving just one pixel in 1bpp), we always
+                           collect one full long for DST and that might
+                           overlap with the current long from SRC. We store
+                           this value in 'd0'. */
+                       d0 = *src++;
+                       /* Leading bits */
+                       if (shift > 0) {
+                               /* Single source word */
+                               *dst = comp(d0 >> right, *dst, first);
+                               dst++;
+                               n -= bits - dst_idx;
+                       } else {
+                               /* 2 source words */
+                               d1 = *src++;
+                               *dst = comp(d0 << left | *dst >> right, *dst, first);
+                               d0 = d1;
+                               dst++;
+                               n -= bits - dst_idx;
+                       }
+
+                       /* Main chunk */
+                       m = n % bits;
+                       n /= bits;
+                       while (n >= 4) {
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                       }
+
+                       /* Trailing bits */
+                       if (last) {
+                               if (m <= right) {
+                                       /* Single source word */
+                                       *dst = comp(d0 << left, *dst, last);
+                               } else {
+                                       /* 2 source words */
+                                       d1 = *src;
+                                       *dst = comp(d0 << left | d1 >> right,
+                                                   *dst, last);
+                               }
+                       }
+               }
+       }
+}
+
+    /*
+     *  Generic bitwise copy algorithm, operating backward
+     */
+
+static void
+bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+               const unsigned long *src, int src_idx, int bits, unsigned n)
+{
+       unsigned long first, last;
+       int shift;
+
+       dst += (n-1)/bits;
+       src += (n-1)/bits;
+       if ((n-1) % bits) {
+               dst_idx += (n-1) % bits;
+               dst += dst_idx >> (ffs(bits) - 1);
+               dst_idx &= bits - 1;
+               src_idx += (n-1) % bits;
+               src += src_idx >> (ffs(bits) - 1);
+               src_idx &= bits - 1;
+       }
+
+       shift = dst_idx-src_idx;
+
+       first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
+       last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
+
+       if (!shift) {
+               /* Same alignment for source and dest */
+               if ((unsigned long)dst_idx+1 >= n) {
+                       /* Single word */
+                       if (last)
+                               first &= last;
+                       *dst = comp(*src, *dst, first);
+               } else {
+                       /* Multiple destination words */
+
+                       /* Leading bits */
+                       if (first != ~0UL) {
+                               *dst = comp(*src, *dst, first);
+                               dst--;
+                               src--;
+                               n -= dst_idx+1;
+                       }
+
+                       /* Main chunk */
+                       n /= bits;
+                       while (n >= 8) {
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               n -= 8;
+                       }
+                       while (n--)
+                               *dst-- = *src--;
+                       /* Trailing bits */
+                       if (last)
+                               *dst = comp(*src, *dst, last);
+               }
+       } else {
+               /* Different alignment for source and dest */
+
+               int const left = -shift & (bits-1);
+               int const right = shift & (bits-1);
+
+               if ((unsigned long)dst_idx+1 >= n) {
+                       /* Single destination word */
+                       if (last)
+                               first &= last;
+                       if (shift < 0) {
+                               /* Single source word */
+                               *dst = comp(*src << left, *dst, first);
+                       } else if (1+(unsigned long)src_idx >= n) {
+                               /* Single source word */
+                               *dst = comp(*src >> right, *dst, first);
+                       } else {
+                               /* 2 source words */
+                               *dst = comp(*src >> right | *(src-1) << left,
+                                           *dst, first);
+                       }
+               } else {
+                       /* Multiple destination words */
+                       /** We must always remember the last value read,
+                           because in case SRC and DST overlap bitwise (e.g.
+                           when moving just one pixel in 1bpp), we always
+                           collect one full long for DST and that might
+                           overlap with the current long from SRC. We store
+                           this value in 'd0'. */
+                       unsigned long d0, d1;
+                       int m;
+
+                       d0 = *src--;
+                       /* Leading bits */
+                       if (shift < 0) {
+                               /* Single source word */
+                               *dst = comp(d0 << left, *dst, first);
+                       } else {
+                               /* 2 source words */
+                               d1 = *src--;
+                               *dst = comp(d0 >> right | d1 << left, *dst,
+                                           first);
+                               d0 = d1;
+                       }
+                       dst--;
+                       n -= dst_idx+1;
+
+                       /* Main chunk */
+                       m = n % bits;
+                       n /= bits;
+                       while (n >= 4) {
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                       }
+
+                       /* Trailing bits */
+                       if (last) {
+                               if (m <= left) {
+                                       /* Single source word */
+                                       *dst = comp(d0 >> right, *dst, last);
+                               } else {
+                                       /* 2 source words */
+                                       d1 = *src;
+                                       *dst = comp(d0 >> right | d1 << left,
+                                                   *dst, last);
+                               }
+                       }
+               }
+       }
+}
+
+void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+       u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+       u32 height = area->height, width = area->width;
+       unsigned long const bits_per_line = p->fix.line_length*8u;
+       unsigned long *dst = NULL, *src = NULL;
+       int bits = BITS_PER_LONG, bytes = bits >> 3;
+       int dst_idx = 0, src_idx = 0, rev_copy = 0;
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       /* if the beginning of the target area might overlap with the end of
+       the source area, be have to copy the area reverse. */
+       if ((dy == sy && dx > sx) || (dy > sy)) {
+               dy += height;
+               sy += height;
+               rev_copy = 1;
+       }
+
+       /* split the base of the framebuffer into a long-aligned address and
+          the index of the first bit */
+       dst = src = (unsigned long *)((unsigned long)p->screen_base &
+                                     ~(bytes-1));
+       dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+       /* add offset of source and target area */
+       dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+       src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+
+       if (rev_copy) {
+               while (height--) {
+                       dst_idx -= bits_per_line;
+                       src_idx -= bits_per_line;
+                       dst += dst_idx >> (ffs(bits) - 1);
+                       dst_idx &= (bytes - 1);
+                       src += src_idx >> (ffs(bits) - 1);
+                       src_idx &= (bytes - 1);
+                       bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
+                               width*p->var.bits_per_pixel);
+               }
+       } else {
+               while (height--) {
+                       dst += dst_idx >> (ffs(bits) - 1);
+                       dst_idx &= (bytes - 1);
+                       src += src_idx >> (ffs(bits) - 1);
+                       src_idx &= (bytes - 1);
+                       bitcpy(p, dst, dst_idx, src, src_idx, bits,
+                               width*p->var.bits_per_pixel);
+                       dst_idx += bits_per_line;
+                       src_idx += bits_per_line;
+               }
+       }
+}
+
+EXPORT_SYMBOL(sys_copyarea);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/fbdev/core/sysfillrect.c b/drivers/video/fbdev/core/sysfillrect.c
new file mode 100644 (file)
index 0000000..33ee3d3
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  Generic fillrect for frame buffers in system RAM with packed pixels of
+ *  any depth.
+ *
+ *  Based almost entirely from cfbfillrect.c (which is based almost entirely
+ *  on Geert Uytterhoeven's fillrect routine)
+ *
+ *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include "fb_draw.h"
+
+    /*
+     *  Aligned pattern fill using 32/64-bit memory accesses
+     */
+
+static void
+bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
+               unsigned long pat, unsigned n, int bits)
+{
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               /* Single word */
+               if (last)
+                       first &= last;
+               *dst = comp(pat, *dst, first);
+       } else {
+               /* Multiple destination words */
+
+               /* Leading bits */
+               if (first!= ~0UL) {
+                       *dst = comp(pat, *dst, first);
+                       dst++;
+                       n -= bits - dst_idx;
+               }
+
+               /* Main chunk */
+               n /= bits;
+               while (n >= 8) {
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       *dst++ = pat;
+                       n -= 8;
+               }
+               while (n--)
+                       *dst++ = pat;
+               /* Trailing bits */
+               if (last)
+                       *dst = comp(pat, *dst, last);
+       }
+}
+
+
+    /*
+     *  Unaligned generic pattern fill using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
+                 unsigned long pat, int left, int right, unsigned n, int bits)
+{
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               /* Single word */
+               if (last)
+                       first &= last;
+               *dst = comp(pat, *dst, first);
+       } else {
+               /* Multiple destination words */
+               /* Leading bits */
+               if (first) {
+                       *dst = comp(pat, *dst, first);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       n -= bits - dst_idx;
+               }
+
+               /* Main chunk */
+               n /= bits;
+               while (n >= 4) {
+                       *dst++ = pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ = pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ = pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ = pat;
+                       pat = pat << left | pat >> right;
+                       n -= 4;
+               }
+               while (n--) {
+                       *dst++ = pat;
+                       pat = pat << left | pat >> right;
+               }
+
+               /* Trailing bits */
+               if (last)
+                       *dst = comp(pat, *dst, last);
+       }
+}
+
+    /*
+     *  Aligned pattern invert using 32/64-bit memory accesses
+     */
+static void
+bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+                   unsigned long pat, unsigned n, int bits)
+{
+       unsigned long val = pat;
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               /* Single word */
+               if (last)
+                       first &= last;
+               *dst = comp(*dst ^ val, *dst, first);
+       } else {
+               /* Multiple destination words */
+               /* Leading bits */
+               if (first!=0UL) {
+                       *dst = comp(*dst ^ val, *dst, first);
+                       dst++;
+                       n -= bits - dst_idx;
+               }
+
+               /* Main chunk */
+               n /= bits;
+               while (n >= 8) {
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       n -= 8;
+               }
+               while (n--)
+                       *dst++ ^= val;
+               /* Trailing bits */
+               if (last)
+                       *dst = comp(*dst ^ val, *dst, last);
+       }
+}
+
+
+    /*
+     *  Unaligned generic pattern invert using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+                     unsigned long pat, int left, int right, unsigned n,
+                     int bits)
+{
+       unsigned long first, last;
+
+       if (!n)
+               return;
+
+       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
+
+       if (dst_idx+n <= bits) {
+               /* Single word */
+               if (last)
+                       first &= last;
+               *dst = comp(*dst ^ pat, *dst, first);
+       } else {
+               /* Multiple destination words */
+
+               /* Leading bits */
+               if (first != 0UL) {
+                       *dst = comp(*dst ^ pat, *dst, first);
+                       dst++;
+                       pat = pat << left | pat >> right;
+                       n -= bits - dst_idx;
+               }
+
+               /* Main chunk */
+               n /= bits;
+               while (n >= 4) {
+                       *dst++ ^= pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ ^= pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ ^= pat;
+                       pat = pat << left | pat >> right;
+                       *dst++ ^= pat;
+                       pat = pat << left | pat >> right;
+                       n -= 4;
+               }
+               while (n--) {
+                       *dst ^= pat;
+                       pat = pat << left | pat >> right;
+               }
+
+               /* Trailing bits */
+               if (last)
+                       *dst = comp(*dst ^ pat, *dst, last);
+       }
+}
+
+void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+       unsigned long pat, pat2, fg;
+       unsigned long width = rect->width, height = rect->height;
+       int bits = BITS_PER_LONG, bytes = bits >> 3;
+       u32 bpp = p->var.bits_per_pixel;
+       unsigned long *dst;
+       int dst_idx, left;
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+               fg = ((u32 *) (p->pseudo_palette))[rect->color];
+       else
+               fg = rect->color;
+
+       pat = pixel_to_pat( bpp, fg);
+
+       dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
+       dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
+       dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
+       /* FIXME For now we support 1-32 bpp only */
+       left = bits % bpp;
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+       if (!left) {
+               void (*fill_op32)(struct fb_info *p, unsigned long *dst,
+                                 int dst_idx, unsigned long pat, unsigned n,
+                                 int bits) = NULL;
+
+               switch (rect->rop) {
+               case ROP_XOR:
+                       fill_op32 = bitfill_aligned_rev;
+                       break;
+               case ROP_COPY:
+                       fill_op32 = bitfill_aligned;
+                       break;
+               default:
+                       printk( KERN_ERR "cfb_fillrect(): unknown rop, "
+                               "defaulting to ROP_COPY\n");
+                       fill_op32 = bitfill_aligned;
+                       break;
+               }
+               while (height--) {
+                       dst += dst_idx >> (ffs(bits) - 1);
+                       dst_idx &= (bits - 1);
+                       fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
+                       dst_idx += p->fix.line_length*8;
+               }
+       } else {
+               int right, r;
+               void (*fill_op)(struct fb_info *p, unsigned long *dst,
+                               int dst_idx, unsigned long pat, int left,
+                               int right, unsigned n, int bits) = NULL;
+#ifdef __LITTLE_ENDIAN
+               right = left;
+               left = bpp - right;
+#else
+               right = bpp - left;
+#endif
+               switch (rect->rop) {
+               case ROP_XOR:
+                       fill_op = bitfill_unaligned_rev;
+                       break;
+               case ROP_COPY:
+                       fill_op = bitfill_unaligned;
+                       break;
+               default:
+                       printk(KERN_ERR "sys_fillrect(): unknown rop, "
+                               "defaulting to ROP_COPY\n");
+                       fill_op = bitfill_unaligned;
+                       break;
+               }
+               while (height--) {
+                       dst += dst_idx / bits;
+                       dst_idx &= (bits - 1);
+                       r = dst_idx % bpp;
+                       /* rotate pattern to the correct start position */
+                       pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
+                       fill_op(p, dst, dst_idx, pat2, left, right,
+                               width*bpp, bits);
+                       dst_idx += p->fix.line_length*8;
+               }
+       }
+}
+
+EXPORT_SYMBOL(sys_fillrect);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/sysimgblt.c b/drivers/video/fbdev/core/sysimgblt.c
new file mode 100644 (file)
index 0000000..a4d05b1
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ *  Generic 1-bit or 8-bit source to 1-32 bit destination expansion
+ *  for frame buffer located in system RAM with packed pixels of any depth.
+ *
+ *  Based almost entirely on cfbimgblt.c
+ *
+ *      Copyright (C)  April 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+static const u32 cfb_tab8_be[] = {
+    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+};
+
+static const u32 cfb_tab8_le[] = {
+    0x00000000,0xff000000,0x00ff0000,0xffff0000,
+    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+};
+
+static const u32 cfb_tab16_be[] = {
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+};
+
+static const u32 cfb_tab16_le[] = {
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+};
+
+static const u32 cfb_tab32[] = {
+       0x00000000, 0xffffffff
+};
+
+static void color_imageblit(const struct fb_image *image, struct fb_info *p,
+                           void *dst1, u32 start_index, u32 pitch_index)
+{
+       /* Draw the penguin */
+       u32 *dst, *dst2;
+       u32 color = 0, val, shift;
+       int i, n, bpp = p->var.bits_per_pixel;
+       u32 null_bits = 32 - bpp;
+       u32 *palette = (u32 *) p->pseudo_palette;
+       const u8 *src = image->data;
+
+       dst2 = dst1;
+       for (i = image->height; i--; ) {
+               n = image->width;
+               dst = dst1;
+               shift = 0;
+               val = 0;
+
+               if (start_index) {
+                       u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
+                                                        start_index));
+                       val = *dst & start_mask;
+                       shift = start_index;
+               }
+               while (n--) {
+                       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+                           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+                               color = palette[*src];
+                       else
+                               color = *src;
+                       color <<= FB_LEFT_POS(p, bpp);
+                       val |= FB_SHIFT_HIGH(p, color, shift);
+                       if (shift >= null_bits) {
+                               *dst++ = val;
+
+                               val = (shift == null_bits) ? 0 :
+                                       FB_SHIFT_LOW(p, color, 32 - shift);
+                       }
+                       shift += bpp;
+                       shift &= (32 - 1);
+                       src++;
+               }
+               if (shift) {
+                       u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
+
+                       *dst &= end_mask;
+                       *dst |= val;
+               }
+               dst1 += p->fix.line_length;
+               if (pitch_index) {
+                       dst2 += p->fix.line_length;
+                       dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+
+                       start_index += pitch_index;
+                       start_index &= 32 - 1;
+               }
+       }
+}
+
+static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
+                                 void *dst1, u32 fgcolor, u32 bgcolor,
+                                 u32 start_index, u32 pitch_index)
+{
+       u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+       u32 *dst, *dst2;
+       u32 val, pitch = p->fix.line_length;
+       u32 null_bits = 32 - bpp;
+       u32 spitch = (image->width+7)/8;
+       const u8 *src = image->data, *s;
+       u32 i, j, l;
+
+       dst2 = dst1;
+       fgcolor <<= FB_LEFT_POS(p, bpp);
+       bgcolor <<= FB_LEFT_POS(p, bpp);
+
+       for (i = image->height; i--; ) {
+               shift = val = 0;
+               l = 8;
+               j = image->width;
+               dst = dst1;
+               s = src;
+
+               /* write leading bits */
+               if (start_index) {
+                       u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
+                                                        start_index));
+                       val = *dst & start_mask;
+                       shift = start_index;
+               }
+
+               while (j--) {
+                       l--;
+                       color = (*s & (1 << l)) ? fgcolor : bgcolor;
+                       val |= FB_SHIFT_HIGH(p, color, shift);
+
+                       /* Did the bitshift spill bits to the next long? */
+                       if (shift >= null_bits) {
+                               *dst++ = val;
+                               val = (shift == null_bits) ? 0 :
+                                       FB_SHIFT_LOW(p, color, 32 - shift);
+                       }
+                       shift += bpp;
+                       shift &= (32 - 1);
+                       if (!l) { l = 8; s++; }
+               }
+
+               /* write trailing bits */
+               if (shift) {
+                       u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
+
+                       *dst &= end_mask;
+                       *dst |= val;
+               }
+
+               dst1 += pitch;
+               src += spitch;
+               if (pitch_index) {
+                       dst2 += pitch;
+                       dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+                       start_index += pitch_index;
+                       start_index &= 32 - 1;
+               }
+
+       }
+}
+
+/*
+ * fast_imageblit - optimized monochrome color expansion
+ *
+ * Only if:  bits_per_pixel == 8, 16, or 32
+ *           image->width is divisible by pixel/dword (ppw);
+ *           fix->line_legth is divisible by 4;
+ *           beginning and end of a scanline is dword aligned
+ */
+static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
+                                 void *dst1, u32 fgcolor, u32 bgcolor)
+{
+       u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+       u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+       u32 bit_mask, end_mask, eorx, shift;
+       const char *s = image->data, *src;
+       u32 *dst;
+       const u32 *tab = NULL;
+       int i, j, k;
+
+       switch (bpp) {
+       case 8:
+               tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
+               break;
+       case 16:
+               tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
+               break;
+       case 32:
+       default:
+               tab = cfb_tab32;
+               break;
+       }
+
+       for (i = ppw-1; i--; ) {
+               fgx <<= bpp;
+               bgx <<= bpp;
+               fgx |= fgcolor;
+               bgx |= bgcolor;
+       }
+
+       bit_mask = (1 << ppw) - 1;
+       eorx = fgx ^ bgx;
+       k = image->width/ppw;
+
+       for (i = image->height; i--; ) {
+               dst = dst1;
+               shift = 8;
+               src = s;
+
+               for (j = k; j--; ) {
+                       shift -= ppw;
+                       end_mask = tab[(*src >> shift) & bit_mask];
+                       *dst++ = (end_mask & eorx) ^ bgx;
+                       if (!shift) {
+                               shift = 8;
+                               src++;
+                       }
+               }
+               dst1 += p->fix.line_length;
+               s += spitch;
+       }
+}
+
+void sys_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+       u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+       u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
+       u32 width = image->width;
+       u32 dx = image->dx, dy = image->dy;
+       void *dst1;
+
+       if (p->state != FBINFO_STATE_RUNNING)
+               return;
+
+       bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
+       start_index = bitstart & (32 - 1);
+       pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
+
+       bitstart /= 8;
+       bitstart &= ~(bpl - 1);
+       dst1 = (void __force *)p->screen_base + bitstart;
+
+       if (p->fbops->fb_sync)
+               p->fbops->fb_sync(p);
+
+       if (image->depth == 1) {
+               if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+                   p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+                       fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
+                       bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
+               } else {
+                       fgcolor = image->fg_color;
+                       bgcolor = image->bg_color;
+               }
+
+               if (32 % bpp == 0 && !start_index && !pitch_index &&
+                   ((width & (32/bpp-1)) == 0) &&
+                   bpp >= 8 && bpp <= 32)
+                       fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+               else
+                       slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+                                       start_index, pitch_index);
+       } else
+               color_imageblit(image, p, dst1, start_index, pitch_index);
+}
+
+EXPORT_SYMBOL(sys_imageblit);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/fbdev/fb_ddc.c b/drivers/video/fbdev/fb_ddc.c
deleted file mode 100644 (file)
index 2b106f0..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * drivers/video/fb_ddc.c - DDC/EDID read support.
- *
- *  Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
- *
- * 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.
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/fb.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/slab.h>
-
-#include "edid.h"
-
-#define DDC_ADDR       0x50
-
-static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
-{
-       unsigned char start = 0x0;
-       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
-       struct i2c_msg msgs[] = {
-               {
-                       .addr   = DDC_ADDR,
-                       .flags  = 0,
-                       .len    = 1,
-                       .buf    = &start,
-               }, {
-                       .addr   = DDC_ADDR,
-                       .flags  = I2C_M_RD,
-                       .len    = EDID_LENGTH,
-                       .buf    = buf,
-               }
-       };
-
-       if (!buf) {
-               dev_warn(&adapter->dev, "unable to allocate memory for EDID "
-                        "block.\n");
-               return NULL;
-       }
-
-       if (i2c_transfer(adapter, msgs, 2) == 2)
-               return buf;
-
-       dev_warn(&adapter->dev, "unable to read EDID block.\n");
-       kfree(buf);
-       return NULL;
-}
-
-unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
-{
-       struct i2c_algo_bit_data *algo_data = adapter->algo_data;
-       unsigned char *edid = NULL;
-       int i, j;
-
-       algo_data->setscl(algo_data->data, 1);
-
-       for (i = 0; i < 3; i++) {
-               /* For some old monitors we need the
-                * following process to initialize/stop DDC
-                */
-               algo_data->setsda(algo_data->data, 1);
-               msleep(13);
-
-               algo_data->setscl(algo_data->data, 1);
-               for (j = 0; j < 5; j++) {
-                       msleep(10);
-                       if (algo_data->getscl(algo_data->data))
-                               break;
-               }
-               if (j == 5)
-                       continue;
-
-               algo_data->setsda(algo_data->data, 0);
-               msleep(15);
-               algo_data->setscl(algo_data->data, 0);
-               msleep(15);
-               algo_data->setsda(algo_data->data, 1);
-               msleep(15);
-
-               /* Do the real work */
-               edid = fb_do_probe_ddc_edid(adapter);
-               algo_data->setsda(algo_data->data, 0);
-               algo_data->setscl(algo_data->data, 0);
-               msleep(15);
-
-               algo_data->setscl(algo_data->data, 1);
-               for (j = 0; j < 10; j++) {
-                       msleep(10);
-                       if (algo_data->getscl(algo_data->data))
-                               break;
-               }
-
-               algo_data->setsda(algo_data->data, 1);
-               msleep(15);
-               algo_data->setscl(algo_data->data, 0);
-               algo_data->setsda(algo_data->data, 0);
-               if (edid)
-                       break;
-       }
-       /* Release the DDC lines when done or the Apple Cinema HD display
-        * will switch off
-        */
-       algo_data->setsda(algo_data->data, 1);
-       algo_data->setscl(algo_data->data, 1);
-
-       adapter->class |= I2C_CLASS_DDC;
-       return edid;
-}
-
-EXPORT_SYMBOL_GPL(fb_ddc_read);
-
-MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
-MODULE_DESCRIPTION("DDC/EDID reading support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/fb_defio.c b/drivers/video/fbdev/fb_defio.c
deleted file mode 100644 (file)
index 900aa4e..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- *  linux/drivers/video/fb_defio.c
- *
- *  Copyright (C) 2006 Jaya Kumar
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/list.h>
-
-/* to support deferred IO */
-#include <linux/rmap.h>
-#include <linux/pagemap.h>
-
-static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
-{
-       void *screen_base = (void __force *) info->screen_base;
-       struct page *page;
-
-       if (is_vmalloc_addr(screen_base + offs))
-               page = vmalloc_to_page(screen_base + offs);
-       else
-               page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT);
-
-       return page;
-}
-
-/* this is to find and return the vmalloc-ed fb pages */
-static int fb_deferred_io_fault(struct vm_area_struct *vma,
-                               struct vm_fault *vmf)
-{
-       unsigned long offset;
-       struct page *page;
-       struct fb_info *info = vma->vm_private_data;
-
-       offset = vmf->pgoff << PAGE_SHIFT;
-       if (offset >= info->fix.smem_len)
-               return VM_FAULT_SIGBUS;
-
-       page = fb_deferred_io_page(info, offset);
-       if (!page)
-               return VM_FAULT_SIGBUS;
-
-       get_page(page);
-
-       if (vma->vm_file)
-               page->mapping = vma->vm_file->f_mapping;
-       else
-               printk(KERN_ERR "no mapping available\n");
-
-       BUG_ON(!page->mapping);
-       page->index = vmf->pgoff;
-
-       vmf->page = page;
-       return 0;
-}
-
-int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
-{
-       struct fb_info *info = file->private_data;
-       struct inode *inode = file_inode(file);
-       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (err)
-               return err;
-
-       /* Skip if deferred io is compiled-in but disabled on this fbdev */
-       if (!info->fbdefio)
-               return 0;
-
-       mutex_lock(&inode->i_mutex);
-       /* Kill off the delayed work */
-       cancel_delayed_work_sync(&info->deferred_work);
-
-       /* Run it immediately */
-       err = schedule_delayed_work(&info->deferred_work, 0);
-       mutex_unlock(&inode->i_mutex);
-       return err;
-}
-EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
-
-/* vm_ops->page_mkwrite handler */
-static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
-                                 struct vm_fault *vmf)
-{
-       struct page *page = vmf->page;
-       struct fb_info *info = vma->vm_private_data;
-       struct fb_deferred_io *fbdefio = info->fbdefio;
-       struct page *cur;
-
-       /* this is a callback we get when userspace first tries to
-       write to the page. we schedule a workqueue. that workqueue
-       will eventually mkclean the touched pages and execute the
-       deferred framebuffer IO. then if userspace touches a page
-       again, we repeat the same scheme */
-
-       file_update_time(vma->vm_file);
-
-       /* protect against the workqueue changing the page list */
-       mutex_lock(&fbdefio->lock);
-
-       /* first write in this cycle, notify the driver */
-       if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
-               fbdefio->first_io(info);
-
-       /*
-        * We want the page to remain locked from ->page_mkwrite until
-        * the PTE is marked dirty to avoid page_mkclean() being called
-        * before the PTE is updated, which would leave the page ignored
-        * by defio.
-        * Do this by locking the page here and informing the caller
-        * about it with VM_FAULT_LOCKED.
-        */
-       lock_page(page);
-
-       /* we loop through the pagelist before adding in order
-       to keep the pagelist sorted */
-       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
-               /* this check is to catch the case where a new
-               process could start writing to the same page
-               through a new pte. this new access can cause the
-               mkwrite even when the original ps's pte is marked
-               writable */
-               if (unlikely(cur == page))
-                       goto page_already_added;
-               else if (cur->index > page->index)
-                       break;
-       }
-
-       list_add_tail(&page->lru, &cur->lru);
-
-page_already_added:
-       mutex_unlock(&fbdefio->lock);
-
-       /* come back after delay to process the deferred IO */
-       schedule_delayed_work(&info->deferred_work, fbdefio->delay);
-       return VM_FAULT_LOCKED;
-}
-
-static const struct vm_operations_struct fb_deferred_io_vm_ops = {
-       .fault          = fb_deferred_io_fault,
-       .page_mkwrite   = fb_deferred_io_mkwrite,
-};
-
-static int fb_deferred_io_set_page_dirty(struct page *page)
-{
-       if (!PageDirty(page))
-               SetPageDirty(page);
-       return 0;
-}
-
-static const struct address_space_operations fb_deferred_io_aops = {
-       .set_page_dirty = fb_deferred_io_set_page_dirty,
-};
-
-static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
-       vma->vm_ops = &fb_deferred_io_vm_ops;
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-       if (!(info->flags & FBINFO_VIRTFB))
-               vma->vm_flags |= VM_IO;
-       vma->vm_private_data = info;
-       return 0;
-}
-
-/* workqueue callback */
-static void fb_deferred_io_work(struct work_struct *work)
-{
-       struct fb_info *info = container_of(work, struct fb_info,
-                                               deferred_work.work);
-       struct list_head *node, *next;
-       struct page *cur;
-       struct fb_deferred_io *fbdefio = info->fbdefio;
-
-       /* here we mkclean the pages, then do all deferred IO */
-       mutex_lock(&fbdefio->lock);
-       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
-               lock_page(cur);
-               page_mkclean(cur);
-               unlock_page(cur);
-       }
-
-       /* driver's callback with pagelist */
-       fbdefio->deferred_io(info, &fbdefio->pagelist);
-
-       /* clear the list */
-       list_for_each_safe(node, next, &fbdefio->pagelist) {
-               list_del(node);
-       }
-       mutex_unlock(&fbdefio->lock);
-}
-
-void fb_deferred_io_init(struct fb_info *info)
-{
-       struct fb_deferred_io *fbdefio = info->fbdefio;
-
-       BUG_ON(!fbdefio);
-       mutex_init(&fbdefio->lock);
-       info->fbops->fb_mmap = fb_deferred_io_mmap;
-       INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
-       INIT_LIST_HEAD(&fbdefio->pagelist);
-       if (fbdefio->delay == 0) /* set a default of 1 s */
-               fbdefio->delay = HZ;
-}
-EXPORT_SYMBOL_GPL(fb_deferred_io_init);
-
-void fb_deferred_io_open(struct fb_info *info,
-                        struct inode *inode,
-                        struct file *file)
-{
-       file->f_mapping->a_ops = &fb_deferred_io_aops;
-}
-EXPORT_SYMBOL_GPL(fb_deferred_io_open);
-
-void fb_deferred_io_cleanup(struct fb_info *info)
-{
-       struct fb_deferred_io *fbdefio = info->fbdefio;
-       struct page *page;
-       int i;
-
-       BUG_ON(!fbdefio);
-       cancel_delayed_work_sync(&info->deferred_work);
-
-       /* clear out the mapping that we setup */
-       for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
-               page = fb_deferred_io_page(info, i);
-               page->mapping = NULL;
-       }
-
-       info->fbops->fb_mmap = NULL;
-       mutex_destroy(&fbdefio->lock);
-}
-EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/fb_draw.h b/drivers/video/fbdev/fb_draw.h
deleted file mode 100644 (file)
index 624ee11..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-#ifndef _FB_DRAW_H
-#define _FB_DRAW_H
-
-#include <asm/types.h>
-#include <linux/fb.h>
-#include <linux/bug.h>
-
-    /*
-     *  Compose two values, using a bitmask as decision value
-     *  This is equivalent to (a & mask) | (b & ~mask)
-     */
-
-static inline unsigned long
-comp(unsigned long a, unsigned long b, unsigned long mask)
-{
-    return ((a ^ b) & mask) ^ b;
-}
-
-    /*
-     *  Create a pattern with the given pixel's color
-     */
-
-#if BITS_PER_LONG == 64
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
-       switch (bpp) {
-       case 1:
-               return 0xfffffffffffffffful*pixel;
-       case 2:
-               return 0x5555555555555555ul*pixel;
-       case 4:
-               return 0x1111111111111111ul*pixel;
-       case 8:
-               return 0x0101010101010101ul*pixel;
-       case 12:
-               return 0x1001001001001001ul*pixel;
-       case 16:
-               return 0x0001000100010001ul*pixel;
-       case 24:
-               return 0x0001000001000001ul*pixel;
-       case 32:
-               return 0x0000000100000001ul*pixel;
-       default:
-               WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp);
-               return 0;
-    }
-}
-#else
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
-       switch (bpp) {
-       case 1:
-               return 0xfffffffful*pixel;
-       case 2:
-               return 0x55555555ul*pixel;
-       case 4:
-               return 0x11111111ul*pixel;
-       case 8:
-               return 0x01010101ul*pixel;
-       case 12:
-               return 0x01001001ul*pixel;
-       case 16:
-               return 0x00010001ul*pixel;
-       case 24:
-               return 0x01000001ul*pixel;
-       case 32:
-               return 0x00000001ul*pixel;
-       default:
-               WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp);
-               return 0;
-    }
-}
-#endif
-
-#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
-#if BITS_PER_LONG == 64
-#define REV_PIXELS_MASK1 0x5555555555555555ul
-#define REV_PIXELS_MASK2 0x3333333333333333ul
-#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful
-#else
-#define REV_PIXELS_MASK1 0x55555555ul
-#define REV_PIXELS_MASK2 0x33333333ul
-#define REV_PIXELS_MASK4 0x0f0f0f0ful
-#endif
-
-static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
-                                                 u32 bswapmask)
-{
-       if (bswapmask & 1)
-               val = comp(val >> 1, val << 1, REV_PIXELS_MASK1);
-       if (bswapmask & 2)
-               val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
-       if (bswapmask & 3)
-               val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
-       return val;
-}
-
-static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index,
-                                            u32 bswapmask)
-{
-       u32 mask;
-
-       if (!bswapmask) {
-               mask = FB_SHIFT_HIGH(p, ~(u32)0, index);
-       } else {
-               mask = 0xff << FB_LEFT_POS(p, 8);
-               mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
-               mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
-#if defined(__i386__) || defined(__x86_64__)
-               /* Shift argument is limited to 0 - 31 on x86 based CPU's */
-               if(index + bswapmask < 32)
-#endif
-                       mask |= FB_SHIFT_HIGH(p, ~(u32)0,
-                                       (index + bswapmask) & ~(bswapmask));
-       }
-       return mask;
-}
-
-static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p,
-                                                       u32 index,
-                                                       u32 bswapmask)
-{
-       unsigned long mask;
-
-       if (!bswapmask) {
-               mask = FB_SHIFT_HIGH(p, ~0UL, index);
-       } else {
-               mask = 0xff << FB_LEFT_POS(p, 8);
-               mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
-               mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
-#if defined(__i386__) || defined(__x86_64__)
-               /* Shift argument is limited to 0 - 31 on x86 based CPU's */
-               if(index + bswapmask < BITS_PER_LONG)
-#endif
-                       mask |= FB_SHIFT_HIGH(p, ~0UL,
-                                       (index + bswapmask) & ~(bswapmask));
-       }
-       return mask;
-}
-
-
-static inline u32 fb_compute_bswapmask(struct fb_info *info)
-{
-       u32 bswapmask = 0;
-       unsigned bpp = info->var.bits_per_pixel;
-
-       if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) {
-               /*
-                * Reversed order of pixel layout in bytes
-                * works only for 1, 2 and 4 bpp
-                */
-               bswapmask = 7 - bpp + 1;
-       }
-       return bswapmask;
-}
-
-#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
-
-static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
-                                                 u32 bswapmask)
-{
-       return val;
-}
-
-#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i))
-#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i))
-#define fb_compute_bswapmask(...) 0
-
-#endif  /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
-
-#define cpu_to_le_long _cpu_to_le_long(BITS_PER_LONG)
-#define _cpu_to_le_long(x) __cpu_to_le_long(x)
-#define __cpu_to_le_long(x) cpu_to_le##x
-
-#define le_long_to_cpu _le_long_to_cpu(BITS_PER_LONG)
-#define _le_long_to_cpu(x) __le_long_to_cpu(x)
-#define __le_long_to_cpu(x) le##x##_to_cpu
-
-static inline unsigned long rolx(unsigned long word, unsigned int shift, unsigned int x)
-{
-       return (word << shift) | (word >> (x - shift));
-}
-
-#endif /* FB_DRAW_H */
diff --git a/drivers/video/fbdev/fb_notify.c b/drivers/video/fbdev/fb_notify.c
deleted file mode 100644 (file)
index 74c2da5..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  linux/drivers/video/fb_notify.c
- *
- *  Copyright (C) 2006 Antonino Daplas <adaplas@pol.net>
- *
- *     2001 - Documented with DocBook
- *     - Brad Douglas <brad@neruo.com>
- *
- * 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.
- */
-#include <linux/fb.h>
-#include <linux/notifier.h>
-#include <linux/export.h>
-
-static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
-
-/**
- *     fb_register_client - register a client notifier
- *     @nb: notifier block to callback on events
- */
-int fb_register_client(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_register(&fb_notifier_list, nb);
-}
-EXPORT_SYMBOL(fb_register_client);
-
-/**
- *     fb_unregister_client - unregister a client notifier
- *     @nb: notifier block to callback on events
- */
-int fb_unregister_client(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
-}
-EXPORT_SYMBOL(fb_unregister_client);
-
-/**
- * fb_notifier_call_chain - notify clients of fb_events
- *
- */
-int fb_notifier_call_chain(unsigned long val, void *v)
-{
-       return blocking_notifier_call_chain(&fb_notifier_list, val, v);
-}
-EXPORT_SYMBOL_GPL(fb_notifier_call_chain);
diff --git a/drivers/video/fbdev/fb_sys_fops.c b/drivers/video/fbdev/fb_sys_fops.c
deleted file mode 100644 (file)
index ff275d7..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * linux/drivers/video/fb_sys_read.c - Generic file operations where
- * framebuffer is in system RAM
- *
- * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
- *
- * 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.
- *
- */
-#include <linux/fb.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-
-ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
-                   loff_t *ppos)
-{
-       unsigned long p = *ppos;
-       void *src;
-       int err = 0;
-       unsigned long total_size;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return -EPERM;
-
-       total_size = info->screen_size;
-
-       if (total_size == 0)
-               total_size = info->fix.smem_len;
-
-       if (p >= total_size)
-               return 0;
-
-       if (count >= total_size)
-               count = total_size;
-
-       if (count + p > total_size)
-               count = total_size - p;
-
-       src = (void __force *)(info->screen_base + p);
-
-       if (info->fbops->fb_sync)
-               info->fbops->fb_sync(info);
-
-       if (copy_to_user(buf, src, count))
-               err = -EFAULT;
-
-       if  (!err)
-               *ppos += count;
-
-       return (err) ? err : count;
-}
-EXPORT_SYMBOL_GPL(fb_sys_read);
-
-ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
-                    size_t count, loff_t *ppos)
-{
-       unsigned long p = *ppos;
-       void *dst;
-       int err = 0;
-       unsigned long total_size;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return -EPERM;
-
-       total_size = info->screen_size;
-
-       if (total_size == 0)
-               total_size = info->fix.smem_len;
-
-       if (p > total_size)
-               return -EFBIG;
-
-       if (count > total_size) {
-               err = -EFBIG;
-               count = total_size;
-       }
-
-       if (count + p > total_size) {
-               if (!err)
-                       err = -ENOSPC;
-
-               count = total_size - p;
-       }
-
-       dst = (void __force *) (info->screen_base + p);
-
-       if (info->fbops->fb_sync)
-               info->fbops->fb_sync(info);
-
-       if (copy_from_user(dst, buf, count))
-               err = -EFAULT;
-
-       if  (!err)
-               *ppos += count;
-
-       return (err) ? err : count;
-}
-EXPORT_SYMBOL_GPL(fb_sys_write);
-
-MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
-MODULE_DESCRIPTION("Generic file read (fb in system RAM)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/fbcmap.c b/drivers/video/fbdev/fbcmap.c
deleted file mode 100644 (file)
index f89245b..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- *  linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
- *
- *     Created 15 Jun 1997 by Geert Uytterhoeven
- *
- *     2001 - Documented with DocBook
- *     - Brad Douglas <brad@neruo.com>
- *
- *  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.
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/fb.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-static u16 red2[] __read_mostly = {
-    0x0000, 0xaaaa
-};
-static u16 green2[] __read_mostly = {
-    0x0000, 0xaaaa
-};
-static u16 blue2[] __read_mostly = {
-    0x0000, 0xaaaa
-};
-
-static u16 red4[] __read_mostly = {
-    0x0000, 0xaaaa, 0x5555, 0xffff
-};
-static u16 green4[] __read_mostly = {
-    0x0000, 0xaaaa, 0x5555, 0xffff
-};
-static u16 blue4[] __read_mostly = {
-    0x0000, 0xaaaa, 0x5555, 0xffff
-};
-
-static u16 red8[] __read_mostly = {
-    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
-};
-static u16 green8[] __read_mostly = {
-    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
-};
-static u16 blue8[] __read_mostly = {
-    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
-};
-
-static u16 red16[] __read_mostly = {
-    0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
-    0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
-};
-static u16 green16[] __read_mostly = {
-    0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
-    0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
-};
-static u16 blue16[] __read_mostly = {
-    0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
-    0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
-};
-
-static const struct fb_cmap default_2_colors = {
-    .len=2, .red=red2, .green=green2, .blue=blue2
-};
-static const struct fb_cmap default_8_colors = {
-    .len=8, .red=red8, .green=green8, .blue=blue8
-};
-static const struct fb_cmap default_4_colors = {
-    .len=4, .red=red4, .green=green4, .blue=blue4
-};
-static const struct fb_cmap default_16_colors = {
-    .len=16, .red=red16, .green=green16, .blue=blue16
-};
-
-
-
-/**
- *     fb_alloc_cmap - allocate a colormap
- *     @cmap: frame buffer colormap structure
- *     @len: length of @cmap
- *     @transp: boolean, 1 if there is transparency, 0 otherwise
- *     @flags: flags for kmalloc memory allocation
- *
- *     Allocates memory for a colormap @cmap.  @len is the
- *     number of entries in the palette.
- *
- *     Returns negative errno on error, or zero on success.
- *
- */
-
-int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
-{
-       int size = len * sizeof(u16);
-       int ret = -ENOMEM;
-
-       if (cmap->len != len) {
-               fb_dealloc_cmap(cmap);
-               if (!len)
-                       return 0;
-
-               cmap->red = kmalloc(size, flags);
-               if (!cmap->red)
-                       goto fail;
-               cmap->green = kmalloc(size, flags);
-               if (!cmap->green)
-                       goto fail;
-               cmap->blue = kmalloc(size, flags);
-               if (!cmap->blue)
-                       goto fail;
-               if (transp) {
-                       cmap->transp = kmalloc(size, flags);
-                       if (!cmap->transp)
-                               goto fail;
-               } else {
-                       cmap->transp = NULL;
-               }
-       }
-       cmap->start = 0;
-       cmap->len = len;
-       ret = fb_copy_cmap(fb_default_cmap(len), cmap);
-       if (ret)
-               goto fail;
-       return 0;
-
-fail:
-       fb_dealloc_cmap(cmap);
-       return ret;
-}
-
-int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
-       return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
-}
-
-/**
- *      fb_dealloc_cmap - deallocate a colormap
- *      @cmap: frame buffer colormap structure
- *
- *      Deallocates a colormap that was previously allocated with
- *      fb_alloc_cmap().
- *
- */
-
-void fb_dealloc_cmap(struct fb_cmap *cmap)
-{
-       kfree(cmap->red);
-       kfree(cmap->green);
-       kfree(cmap->blue);
-       kfree(cmap->transp);
-
-       cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
-       cmap->len = 0;
-}
-
-/**
- *     fb_copy_cmap - copy a colormap
- *     @from: frame buffer colormap structure
- *     @to: frame buffer colormap structure
- *
- *     Copy contents of colormap from @from to @to.
- */
-
-int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
-{
-       int tooff = 0, fromoff = 0;
-       int size;
-
-       if (to->start > from->start)
-               fromoff = to->start - from->start;
-       else
-               tooff = from->start - to->start;
-       size = to->len - tooff;
-       if (size > (int) (from->len - fromoff))
-               size = from->len - fromoff;
-       if (size <= 0)
-               return -EINVAL;
-       size *= sizeof(u16);
-
-       memcpy(to->red+tooff, from->red+fromoff, size);
-       memcpy(to->green+tooff, from->green+fromoff, size);
-       memcpy(to->blue+tooff, from->blue+fromoff, size);
-       if (from->transp && to->transp)
-               memcpy(to->transp+tooff, from->transp+fromoff, size);
-       return 0;
-}
-
-int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
-{
-       int tooff = 0, fromoff = 0;
-       int size;
-
-       if (to->start > from->start)
-               fromoff = to->start - from->start;
-       else
-               tooff = from->start - to->start;
-       size = to->len - tooff;
-       if (size > (int) (from->len - fromoff))
-               size = from->len - fromoff;
-       if (size <= 0)
-               return -EINVAL;
-       size *= sizeof(u16);
-
-       if (copy_to_user(to->red+tooff, from->red+fromoff, size))
-               return -EFAULT;
-       if (copy_to_user(to->green+tooff, from->green+fromoff, size))
-               return -EFAULT;
-       if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
-               return -EFAULT;
-       if (from->transp && to->transp)
-               if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
-                       return -EFAULT;
-       return 0;
-}
-
-/**
- *     fb_set_cmap - set the colormap
- *     @cmap: frame buffer colormap structure
- *     @info: frame buffer info structure
- *
- *     Sets the colormap @cmap for a screen of device @info.
- *
- *     Returns negative errno on error, or zero on success.
- *
- */
-
-int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
-{
-       int i, start, rc = 0;
-       u16 *red, *green, *blue, *transp;
-       u_int hred, hgreen, hblue, htransp = 0xffff;
-
-       red = cmap->red;
-       green = cmap->green;
-       blue = cmap->blue;
-       transp = cmap->transp;
-       start = cmap->start;
-
-       if (start < 0 || (!info->fbops->fb_setcolreg &&
-                         !info->fbops->fb_setcmap))
-               return -EINVAL;
-       if (info->fbops->fb_setcmap) {
-               rc = info->fbops->fb_setcmap(cmap, info);
-       } else {
-               for (i = 0; i < cmap->len; i++) {
-                       hred = *red++;
-                       hgreen = *green++;
-                       hblue = *blue++;
-                       if (transp)
-                               htransp = *transp++;
-                       if (info->fbops->fb_setcolreg(start++,
-                                                     hred, hgreen, hblue,
-                                                     htransp, info))
-                               break;
-               }
-       }
-       if (rc == 0)
-               fb_copy_cmap(cmap, &info->cmap);
-
-       return rc;
-}
-
-int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
-{
-       int rc, size = cmap->len * sizeof(u16);
-       struct fb_cmap umap;
-
-       if (size < 0 || size < cmap->len)
-               return -E2BIG;
-
-       memset(&umap, 0, sizeof(struct fb_cmap));
-       rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL,
-                               GFP_KERNEL);
-       if (rc)
-               return rc;
-       if (copy_from_user(umap.red, cmap->red, size) ||
-           copy_from_user(umap.green, cmap->green, size) ||
-           copy_from_user(umap.blue, cmap->blue, size) ||
-           (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) {
-               rc = -EFAULT;
-               goto out;
-       }
-       umap.start = cmap->start;
-       if (!lock_fb_info(info)) {
-               rc = -ENODEV;
-               goto out;
-       }
-
-       rc = fb_set_cmap(&umap, info);
-       unlock_fb_info(info);
-out:
-       fb_dealloc_cmap(&umap);
-       return rc;
-}
-
-/**
- *     fb_default_cmap - get default colormap
- *     @len: size of palette for a depth
- *
- *     Gets the default colormap for a specific screen depth.  @len
- *     is the size of the palette for a particular screen depth.
- *
- *     Returns pointer to a frame buffer colormap structure.
- *
- */
-
-const struct fb_cmap *fb_default_cmap(int len)
-{
-    if (len <= 2)
-       return &default_2_colors;
-    if (len <= 4)
-       return &default_4_colors;
-    if (len <= 8)
-       return &default_8_colors;
-    return &default_16_colors;
-}
-
-
-/**
- *     fb_invert_cmaps - invert all defaults colormaps
- *
- *     Invert all default colormaps.
- *
- */
-
-void fb_invert_cmaps(void)
-{
-    u_int i;
-
-    for (i = 0; i < ARRAY_SIZE(red2); i++) {
-       red2[i] = ~red2[i];
-       green2[i] = ~green2[i];
-       blue2[i] = ~blue2[i];
-    }
-    for (i = 0; i < ARRAY_SIZE(red4); i++) {
-       red4[i] = ~red4[i];
-       green4[i] = ~green4[i];
-       blue4[i] = ~blue4[i];
-    }
-    for (i = 0; i < ARRAY_SIZE(red8); i++) {
-       red8[i] = ~red8[i];
-       green8[i] = ~green8[i];
-       blue8[i] = ~blue8[i];
-    }
-    for (i = 0; i < ARRAY_SIZE(red16); i++) {
-       red16[i] = ~red16[i];
-       green16[i] = ~green16[i];
-       blue16[i] = ~blue16[i];
-    }
-}
-
-
-    /*
-     *  Visible symbols for modules
-     */
-
-EXPORT_SYMBOL(fb_alloc_cmap);
-EXPORT_SYMBOL(fb_dealloc_cmap);
-EXPORT_SYMBOL(fb_copy_cmap);
-EXPORT_SYMBOL(fb_set_cmap);
-EXPORT_SYMBOL(fb_default_cmap);
-EXPORT_SYMBOL(fb_invert_cmaps);
diff --git a/drivers/video/fbdev/fbcvt.c b/drivers/video/fbdev/fbcvt.c
deleted file mode 100644 (file)
index 7cb715d..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * linux/drivers/video/fbcvt.c - VESA(TM) Coordinated Video Timings
- *
- * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
- *
- *      Based from the VESA(TM) Coordinated Video Timing Generator by
- *      Graham Loveridge April 9, 2003 available at
- *      http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
- *
- * 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.
- *
- */
-#include <linux/fb.h>
-#include <linux/slab.h>
-
-#define FB_CVT_CELLSIZE               8
-#define FB_CVT_GTF_C                 40
-#define FB_CVT_GTF_J                 20
-#define FB_CVT_GTF_K                128
-#define FB_CVT_GTF_M                600
-#define FB_CVT_MIN_VSYNC_BP         550
-#define FB_CVT_MIN_VPORCH             3
-#define FB_CVT_MIN_BPORCH             6
-
-#define FB_CVT_RB_MIN_VBLANK        460
-#define FB_CVT_RB_HBLANK            160
-#define FB_CVT_RB_V_FPORCH            3
-
-#define FB_CVT_FLAG_REDUCED_BLANK 1
-#define FB_CVT_FLAG_MARGINS       2
-#define FB_CVT_FLAG_INTERLACED    4
-
-struct fb_cvt_data {
-       u32 xres;
-       u32 yres;
-       u32 refresh;
-       u32 f_refresh;
-       u32 pixclock;
-       u32 hperiod;
-       u32 hblank;
-       u32 hfreq;
-       u32 htotal;
-       u32 vtotal;
-       u32 vsync;
-       u32 hsync;
-       u32 h_front_porch;
-       u32 h_back_porch;
-       u32 v_front_porch;
-       u32 v_back_porch;
-       u32 h_margin;
-       u32 v_margin;
-       u32 interlace;
-       u32 aspect_ratio;
-       u32 active_pixels;
-       u32 flags;
-       u32 status;
-};
-
-static const unsigned char fb_cvt_vbi_tab[] = {
-       4,        /* 4:3      */
-       5,        /* 16:9     */
-       6,        /* 16:10    */
-       7,        /* 5:4      */
-       7,        /* 15:9     */
-       8,        /* reserved */
-       9,        /* reserved */
-       10        /* custom   */
-};
-
-/* returns hperiod * 1000 */
-static u32 fb_cvt_hperiod(struct fb_cvt_data *cvt)
-{
-       u32 num = 1000000000/cvt->f_refresh;
-       u32 den;
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
-               num -= FB_CVT_RB_MIN_VBLANK * 1000;
-               den = 2 * (cvt->yres/cvt->interlace + 2 * cvt->v_margin);
-       } else {
-               num -= FB_CVT_MIN_VSYNC_BP * 1000;
-               den = 2 * (cvt->yres/cvt->interlace + cvt->v_margin * 2
-                          + FB_CVT_MIN_VPORCH + cvt->interlace/2);
-       }
-
-       return 2 * (num/den);
-}
-
-/* returns ideal duty cycle * 1000 */
-static u32 fb_cvt_ideal_duty_cycle(struct fb_cvt_data *cvt)
-{
-       u32 c_prime = (FB_CVT_GTF_C - FB_CVT_GTF_J) *
-               (FB_CVT_GTF_K) + 256 * FB_CVT_GTF_J;
-       u32 m_prime = (FB_CVT_GTF_K * FB_CVT_GTF_M);
-       u32 h_period_est = cvt->hperiod;
-
-       return (1000 * c_prime  - ((m_prime * h_period_est)/1000))/256;
-}
-
-static u32 fb_cvt_hblank(struct fb_cvt_data *cvt)
-{
-       u32 hblank = 0;
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
-               hblank = FB_CVT_RB_HBLANK;
-       else {
-               u32 ideal_duty_cycle = fb_cvt_ideal_duty_cycle(cvt);
-               u32 active_pixels = cvt->active_pixels;
-
-               if (ideal_duty_cycle < 20000)
-                       hblank = (active_pixels * 20000)/
-                               (100000 - 20000);
-               else {
-                       hblank = (active_pixels * ideal_duty_cycle)/
-                               (100000 - ideal_duty_cycle);
-               }
-       }
-
-       hblank &= ~((2 * FB_CVT_CELLSIZE) - 1);
-
-       return hblank;
-}
-
-static u32 fb_cvt_hsync(struct fb_cvt_data *cvt)
-{
-       u32 hsync;
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
-               hsync = 32;
-       else
-               hsync = (FB_CVT_CELLSIZE * cvt->htotal)/100;
-
-       hsync &= ~(FB_CVT_CELLSIZE - 1);
-       return hsync;
-}
-
-static u32 fb_cvt_vbi_lines(struct fb_cvt_data *cvt)
-{
-       u32 vbi_lines, min_vbi_lines, act_vbi_lines;
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
-               vbi_lines = (1000 * FB_CVT_RB_MIN_VBLANK)/cvt->hperiod + 1;
-               min_vbi_lines =  FB_CVT_RB_V_FPORCH + cvt->vsync +
-                       FB_CVT_MIN_BPORCH;
-
-       } else {
-               vbi_lines = (FB_CVT_MIN_VSYNC_BP * 1000)/cvt->hperiod + 1 +
-                        FB_CVT_MIN_VPORCH;
-               min_vbi_lines = cvt->vsync + FB_CVT_MIN_BPORCH +
-                       FB_CVT_MIN_VPORCH;
-       }
-
-       if (vbi_lines < min_vbi_lines)
-               act_vbi_lines = min_vbi_lines;
-       else
-               act_vbi_lines = vbi_lines;
-
-       return act_vbi_lines;
-}
-
-static u32 fb_cvt_vtotal(struct fb_cvt_data *cvt)
-{
-       u32 vtotal = cvt->yres/cvt->interlace;
-
-       vtotal += 2 * cvt->v_margin + cvt->interlace/2 + fb_cvt_vbi_lines(cvt);
-       vtotal |= cvt->interlace/2;
-
-       return vtotal;
-}
-
-static u32 fb_cvt_pixclock(struct fb_cvt_data *cvt)
-{
-       u32 pixclock;
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
-               pixclock = (cvt->f_refresh * cvt->vtotal * cvt->htotal)/1000;
-       else
-               pixclock = (cvt->htotal * 1000000)/cvt->hperiod;
-
-       pixclock /= 250;
-       pixclock *= 250;
-       pixclock *= 1000;
-
-       return pixclock;
-}
-
-static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt)
-{
-       u32 xres = cvt->xres;
-       u32 yres = cvt->yres;
-       u32 aspect = -1;
-
-       if (xres == (yres * 4)/3 && !((yres * 4) % 3))
-               aspect = 0;
-       else if (xres == (yres * 16)/9 && !((yres * 16) % 9))
-               aspect = 1;
-       else if (xres == (yres * 16)/10 && !((yres * 16) % 10))
-               aspect = 2;
-       else if (xres == (yres * 5)/4 && !((yres * 5) % 4))
-               aspect = 3;
-       else if (xres == (yres * 15)/9 && !((yres * 15) % 9))
-               aspect = 4;
-       else {
-               printk(KERN_INFO "fbcvt: Aspect ratio not CVT "
-                      "standard\n");
-               aspect = 7;
-               cvt->status = 1;
-       }
-
-       return aspect;
-}
-
-static void fb_cvt_print_name(struct fb_cvt_data *cvt)
-{
-       u32 pixcount, pixcount_mod;
-       int cnt = 255, offset = 0, read = 0;
-       u8 *buf = kzalloc(256, GFP_KERNEL);
-
-       if (!buf)
-               return;
-
-       pixcount = (cvt->xres * (cvt->yres/cvt->interlace))/1000000;
-       pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000;
-       pixcount_mod /= 1000;
-
-       read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ",
-                       cvt->xres, cvt->yres, cvt->refresh);
-       offset += read;
-       cnt -= read;
-
-       if (cvt->status)
-               snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega "
-                        "Pixel Image\n", pixcount, pixcount_mod);
-       else {
-               if (pixcount) {
-                       read = snprintf(buf+offset, cnt, "%d", pixcount);
-                       cnt -= read;
-                       offset += read;
-               }
-
-               read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod);
-               cnt -= read;
-               offset += read;
-
-               if (cvt->aspect_ratio == 0)
-                       read = snprintf(buf+offset, cnt, "3");
-               else if (cvt->aspect_ratio == 3)
-                       read = snprintf(buf+offset, cnt, "4");
-               else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4)
-                       read = snprintf(buf+offset, cnt, "9");
-               else if (cvt->aspect_ratio == 2)
-                       read = snprintf(buf+offset, cnt, "A");
-               else
-                       read = 0;
-               cnt -= read;
-               offset += read;
-
-               if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
-                       read = snprintf(buf+offset, cnt, "-R");
-                       cnt -= read;
-                       offset += read;
-               }
-       }
-
-       printk(KERN_INFO "%s\n", buf);
-       kfree(buf);
-}
-
-static void fb_cvt_convert_to_mode(struct fb_cvt_data *cvt,
-                                  struct fb_videomode *mode)
-{
-       mode->refresh = cvt->f_refresh;
-       mode->pixclock = KHZ2PICOS(cvt->pixclock/1000);
-       mode->left_margin = cvt->h_back_porch;
-       mode->right_margin = cvt->h_front_porch;
-       mode->hsync_len = cvt->hsync;
-       mode->upper_margin = cvt->v_back_porch;
-       mode->lower_margin = cvt->v_front_porch;
-       mode->vsync_len = cvt->vsync;
-
-       mode->sync &= ~(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT);
-
-       if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK)
-               mode->sync |= FB_SYNC_HOR_HIGH_ACT;
-       else
-               mode->sync |= FB_SYNC_VERT_HIGH_ACT;
-}
-
-/*
- * fb_find_mode_cvt - calculate mode using VESA(TM) CVT
- * @mode: pointer to fb_videomode; xres, yres, refresh and vmode must be
- *        pre-filled with the desired values
- * @margins: add margin to calculation (1.8% of xres and yres)
- * @rb: compute with reduced blanking (for flatpanels)
- *
- * RETURNS:
- * 0 for success
- * @mode is filled with computed values.  If interlaced, the refresh field
- * will be filled with the field rate (2x the frame rate)
- *
- * DESCRIPTION:
- * Computes video timings using VESA(TM) Coordinated Video Timings
- */
-int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb)
-{
-       struct fb_cvt_data cvt;
-
-       memset(&cvt, 0, sizeof(cvt));
-
-       if (margins)
-           cvt.flags |= FB_CVT_FLAG_MARGINS;
-
-       if (rb)
-           cvt.flags |= FB_CVT_FLAG_REDUCED_BLANK;
-
-       if (mode->vmode & FB_VMODE_INTERLACED)
-           cvt.flags |= FB_CVT_FLAG_INTERLACED;
-
-       cvt.xres = mode->xres;
-       cvt.yres = mode->yres;
-       cvt.refresh = mode->refresh;
-       cvt.f_refresh = cvt.refresh;
-       cvt.interlace = 1;
-
-       if (!cvt.xres || !cvt.yres || !cvt.refresh) {
-               printk(KERN_INFO "fbcvt: Invalid input parameters\n");
-               return 1;
-       }
-
-       if (!(cvt.refresh == 50 || cvt.refresh == 60 || cvt.refresh == 70 ||
-             cvt.refresh == 85)) {
-               printk(KERN_INFO "fbcvt: Refresh rate not CVT "
-                      "standard\n");
-               cvt.status = 1;
-       }
-
-       cvt.xres &= ~(FB_CVT_CELLSIZE - 1);
-
-       if (cvt.flags & FB_CVT_FLAG_INTERLACED) {
-               cvt.interlace = 2;
-               cvt.f_refresh *= 2;
-       }
-
-       if (cvt.flags & FB_CVT_FLAG_REDUCED_BLANK) {
-               if (cvt.refresh != 60) {
-                       printk(KERN_INFO "fbcvt: 60Hz refresh rate "
-                              "advised for reduced blanking\n");
-                       cvt.status = 1;
-               }
-       }
-
-       if (cvt.flags & FB_CVT_FLAG_MARGINS) {
-               cvt.h_margin = (cvt.xres * 18)/1000;
-               cvt.h_margin &= ~(FB_CVT_CELLSIZE - 1);
-               cvt.v_margin = ((cvt.yres/cvt.interlace)* 18)/1000;
-       }
-
-       cvt.aspect_ratio = fb_cvt_aspect_ratio(&cvt);
-       cvt.active_pixels = cvt.xres + 2 * cvt.h_margin;
-       cvt.hperiod = fb_cvt_hperiod(&cvt);
-       cvt.vsync = fb_cvt_vbi_tab[cvt.aspect_ratio];
-       cvt.vtotal = fb_cvt_vtotal(&cvt);
-       cvt.hblank = fb_cvt_hblank(&cvt);
-       cvt.htotal = cvt.active_pixels + cvt.hblank;
-       cvt.hsync = fb_cvt_hsync(&cvt);
-       cvt.pixclock = fb_cvt_pixclock(&cvt);
-       cvt.hfreq = cvt.pixclock/cvt.htotal;
-       cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin;
-       cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch +
-               2 * cvt.h_margin;
-       cvt.v_back_porch = 3 + cvt.v_margin;
-       cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace -
-           cvt.v_back_porch - cvt.vsync;
-       fb_cvt_print_name(&cvt);
-       fb_cvt_convert_to_mode(&cvt, mode);
-
-       return 0;
-}
diff --git a/drivers/video/fbdev/fbmem.c b/drivers/video/fbdev/fbmem.c
deleted file mode 100644 (file)
index b6d5008..0000000
+++ /dev/null
@@ -1,2002 +0,0 @@
-/*
- *  linux/drivers/video/fbmem.c
- *
- *  Copyright (C) 1994 Martin Schaller
- *
- *     2001 - Documented with DocBook
- *     - Brad Douglas <brad@neruo.com>
- *
- * 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.
- */
-
-#include <linux/module.h>
-
-#include <linux/compat.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/vt.h>
-#include <linux/init.h>
-#include <linux/linux_logo.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/console.h>
-#include <linux/kmod.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/efi.h>
-#include <linux/fb.h>
-
-#include <asm/fb.h>
-
-
-    /*
-     *  Frame buffer device initialization and setup routines
-     */
-
-#define FBPIXMAPSIZE   (1024 * 8)
-
-static DEFINE_MUTEX(registration_lock);
-
-struct fb_info *registered_fb[FB_MAX] __read_mostly;
-EXPORT_SYMBOL(registered_fb);
-
-int num_registered_fb __read_mostly;
-EXPORT_SYMBOL(num_registered_fb);
-
-static struct fb_info *get_fb_info(unsigned int idx)
-{
-       struct fb_info *fb_info;
-
-       if (idx >= FB_MAX)
-               return ERR_PTR(-ENODEV);
-
-       mutex_lock(&registration_lock);
-       fb_info = registered_fb[idx];
-       if (fb_info)
-               atomic_inc(&fb_info->count);
-       mutex_unlock(&registration_lock);
-
-       return fb_info;
-}
-
-static void put_fb_info(struct fb_info *fb_info)
-{
-       if (!atomic_dec_and_test(&fb_info->count))
-               return;
-       if (fb_info->fbops->fb_destroy)
-               fb_info->fbops->fb_destroy(fb_info);
-}
-
-int lock_fb_info(struct fb_info *info)
-{
-       mutex_lock(&info->lock);
-       if (!info->fbops) {
-               mutex_unlock(&info->lock);
-               return 0;
-       }
-       return 1;
-}
-EXPORT_SYMBOL(lock_fb_info);
-
-/*
- * Helpers
- */
-
-int fb_get_color_depth(struct fb_var_screeninfo *var,
-                      struct fb_fix_screeninfo *fix)
-{
-       int depth = 0;
-
-       if (fix->visual == FB_VISUAL_MONO01 ||
-           fix->visual == FB_VISUAL_MONO10)
-               depth = 1;
-       else {
-               if (var->green.length == var->blue.length &&
-                   var->green.length == var->red.length &&
-                   var->green.offset == var->blue.offset &&
-                   var->green.offset == var->red.offset)
-                       depth = var->green.length;
-               else
-                       depth = var->green.length + var->red.length +
-                               var->blue.length;
-       }
-
-       return depth;
-}
-EXPORT_SYMBOL(fb_get_color_depth);
-
-/*
- * Data padding functions.
- */
-void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
-{
-       __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
-}
-EXPORT_SYMBOL(fb_pad_aligned_buffer);
-
-void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
-                               u32 shift_high, u32 shift_low, u32 mod)
-{
-       u8 mask = (u8) (0xfff << shift_high), tmp;
-       int i, j;
-
-       for (i = height; i--; ) {
-               for (j = 0; j < idx; j++) {
-                       tmp = dst[j];
-                       tmp &= mask;
-                       tmp |= *src >> shift_low;
-                       dst[j] = tmp;
-                       tmp = *src << shift_high;
-                       dst[j+1] = tmp;
-                       src++;
-               }
-               tmp = dst[idx];
-               tmp &= mask;
-               tmp |= *src >> shift_low;
-               dst[idx] = tmp;
-               if (shift_high < mod) {
-                       tmp = *src << shift_high;
-                       dst[idx+1] = tmp;
-               }
-               src++;
-               dst += d_pitch;
-       }
-}
-EXPORT_SYMBOL(fb_pad_unaligned_buffer);
-
-/*
- * we need to lock this section since fb_cursor
- * may use fb_imageblit()
- */
-char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
-{
-       u32 align = buf->buf_align - 1, offset;
-       char *addr = buf->addr;
-
-       /* If IO mapped, we need to sync before access, no sharing of
-        * the pixmap is done
-        */
-       if (buf->flags & FB_PIXMAP_IO) {
-               if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
-                       info->fbops->fb_sync(info);
-               return addr;
-       }
-
-       /* See if we fit in the remaining pixmap space */
-       offset = buf->offset + align;
-       offset &= ~align;
-       if (offset + size > buf->size) {
-               /* We do not fit. In order to be able to re-use the buffer,
-                * we must ensure no asynchronous DMA'ing or whatever operation
-                * is in progress, we sync for that.
-                */
-               if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
-                       info->fbops->fb_sync(info);
-               offset = 0;
-       }
-       buf->offset = offset + size;
-       addr += offset;
-
-       return addr;
-}
-EXPORT_SYMBOL(fb_get_buffer_offset);
-
-#ifdef CONFIG_LOGO
-
-static inline unsigned safe_shift(unsigned d, int n)
-{
-       return n < 0 ? d >> -n : d << n;
-}
-
-static void fb_set_logocmap(struct fb_info *info,
-                                  const struct linux_logo *logo)
-{
-       struct fb_cmap palette_cmap;
-       u16 palette_green[16];
-       u16 palette_blue[16];
-       u16 palette_red[16];
-       int i, j, n;
-       const unsigned char *clut = logo->clut;
-
-       palette_cmap.start = 0;
-       palette_cmap.len = 16;
-       palette_cmap.red = palette_red;
-       palette_cmap.green = palette_green;
-       palette_cmap.blue = palette_blue;
-       palette_cmap.transp = NULL;
-
-       for (i = 0; i < logo->clutsize; i += n) {
-               n = logo->clutsize - i;
-               /* palette_cmap provides space for only 16 colors at once */
-               if (n > 16)
-                       n = 16;
-               palette_cmap.start = 32 + i;
-               palette_cmap.len = n;
-               for (j = 0; j < n; ++j) {
-                       palette_cmap.red[j] = clut[0] << 8 | clut[0];
-                       palette_cmap.green[j] = clut[1] << 8 | clut[1];
-                       palette_cmap.blue[j] = clut[2] << 8 | clut[2];
-                       clut += 3;
-               }
-               fb_set_cmap(&palette_cmap, info);
-       }
-}
-
-static void  fb_set_logo_truepalette(struct fb_info *info,
-                                           const struct linux_logo *logo,
-                                           u32 *palette)
-{
-       static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
-       unsigned char redmask, greenmask, bluemask;
-       int redshift, greenshift, blueshift;
-       int i;
-       const unsigned char *clut = logo->clut;
-
-       /*
-        * We have to create a temporary palette since console palette is only
-        * 16 colors long.
-        */
-       /* Bug: Doesn't obey msb_right ... (who needs that?) */
-       redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
-       greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
-       bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
-       redshift   = info->var.red.offset   - (8 - info->var.red.length);
-       greenshift = info->var.green.offset - (8 - info->var.green.length);
-       blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
-
-       for ( i = 0; i < logo->clutsize; i++) {
-               palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
-                                safe_shift((clut[1] & greenmask), greenshift) |
-                                safe_shift((clut[2] & bluemask), blueshift));
-               clut += 3;
-       }
-}
-
-static void fb_set_logo_directpalette(struct fb_info *info,
-                                            const struct linux_logo *logo,
-                                            u32 *palette)
-{
-       int redshift, greenshift, blueshift;
-       int i;
-
-       redshift = info->var.red.offset;
-       greenshift = info->var.green.offset;
-       blueshift = info->var.blue.offset;
-
-       for (i = 32; i < 32 + logo->clutsize; i++)
-               palette[i] = i << redshift | i << greenshift | i << blueshift;
-}
-
-static void fb_set_logo(struct fb_info *info,
-                              const struct linux_logo *logo, u8 *dst,
-                              int depth)
-{
-       int i, j, k;
-       const u8 *src = logo->data;
-       u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
-       u8 fg = 1, d;
-
-       switch (fb_get_color_depth(&info->var, &info->fix)) {
-       case 1:
-               fg = 1;
-               break;
-       case 2:
-               fg = 3;
-               break;
-       default:
-               fg = 7;
-               break;
-       }
-
-       if (info->fix.visual == FB_VISUAL_MONO01 ||
-           info->fix.visual == FB_VISUAL_MONO10)
-               fg = ~((u8) (0xfff << info->var.green.length));
-
-       switch (depth) {
-       case 4:
-               for (i = 0; i < logo->height; i++)
-                       for (j = 0; j < logo->width; src++) {
-                               *dst++ = *src >> 4;
-                               j++;
-                               if (j < logo->width) {
-                                       *dst++ = *src & 0x0f;
-                                       j++;
-                               }
-                       }
-               break;
-       case 1:
-               for (i = 0; i < logo->height; i++) {
-                       for (j = 0; j < logo->width; src++) {
-                               d = *src ^ xor;
-                               for (k = 7; k >= 0; k--) {
-                                       *dst++ = ((d >> k) & 1) ? fg : 0;
-                                       j++;
-                               }
-                       }
-               }
-               break;
-       }
-}
-
-/*
- * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
- * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
- * the visual format and color depth of the framebuffer, the DAC, the
- * pseudo_palette, and the logo data will be adjusted accordingly.
- *
- * Case 1 - linux_logo_clut224:
- * Color exceeds the number of console colors (16), thus we set the hardware DAC
- * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
- *
- * For visuals that require color info from the pseudo_palette, we also construct
- * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
- * will be set.
- *
- * Case 2 - linux_logo_vga16:
- * The number of colors just matches the console colors, thus there is no need
- * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
- * each byte contains color information for two pixels (upper and lower nibble).
- * To be consistent with fb_imageblit() usage, we therefore separate the two
- * nibbles into separate bytes. The "depth" flag will be set to 4.
- *
- * Case 3 - linux_logo_mono:
- * This is similar with Case 2.  Each byte contains information for 8 pixels.
- * We isolate each bit and expand each into a byte. The "depth" flag will
- * be set to 1.
- */
-static struct logo_data {
-       int depth;
-       int needs_directpalette;
-       int needs_truepalette;
-       int needs_cmapreset;
-       const struct linux_logo *logo;
-} fb_logo __read_mostly;
-
-static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
-{
-       u32 size = width * height, i;
-
-       out += size - 1;
-
-       for (i = size; i--; )
-               *out-- = *in++;
-}
-
-static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
-{
-       int i, j, h = height - 1;
-
-       for (i = 0; i < height; i++)
-               for (j = 0; j < width; j++)
-                               out[height * j + h - i] = *in++;
-}
-
-static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
-{
-       int i, j, w = width - 1;
-
-       for (i = 0; i < height; i++)
-               for (j = 0; j < width; j++)
-                       out[height * (w - j) + i] = *in++;
-}
-
-static void fb_rotate_logo(struct fb_info *info, u8 *dst,
-                          struct fb_image *image, int rotate)
-{
-       u32 tmp;
-
-       if (rotate == FB_ROTATE_UD) {
-               fb_rotate_logo_ud(image->data, dst, image->width,
-                                 image->height);
-               image->dx = info->var.xres - image->width - image->dx;
-               image->dy = info->var.yres - image->height - image->dy;
-       } else if (rotate == FB_ROTATE_CW) {
-               fb_rotate_logo_cw(image->data, dst, image->width,
-                                 image->height);
-               tmp = image->width;
-               image->width = image->height;
-               image->height = tmp;
-               tmp = image->dy;
-               image->dy = image->dx;
-               image->dx = info->var.xres - image->width - tmp;
-       } else if (rotate == FB_ROTATE_CCW) {
-               fb_rotate_logo_ccw(image->data, dst, image->width,
-                                  image->height);
-               tmp = image->width;
-               image->width = image->height;
-               image->height = tmp;
-               tmp = image->dx;
-               image->dx = image->dy;
-               image->dy = info->var.yres - image->height - tmp;
-       }
-
-       image->data = dst;
-}
-
-static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
-                           int rotate, unsigned int num)
-{
-       unsigned int x;
-
-       if (rotate == FB_ROTATE_UR) {
-               for (x = 0;
-                    x < num && image->dx + image->width <= info->var.xres;
-                    x++) {
-                       info->fbops->fb_imageblit(info, image);
-                       image->dx += image->width + 8;
-               }
-       } else if (rotate == FB_ROTATE_UD) {
-               for (x = 0; x < num && image->dx >= 0; x++) {
-                       info->fbops->fb_imageblit(info, image);
-                       image->dx -= image->width + 8;
-               }
-       } else if (rotate == FB_ROTATE_CW) {
-               for (x = 0;
-                    x < num && image->dy + image->height <= info->var.yres;
-                    x++) {
-                       info->fbops->fb_imageblit(info, image);
-                       image->dy += image->height + 8;
-               }
-       } else if (rotate == FB_ROTATE_CCW) {
-               for (x = 0; x < num && image->dy >= 0; x++) {
-                       info->fbops->fb_imageblit(info, image);
-                       image->dy -= image->height + 8;
-               }
-       }
-}
-
-static int fb_show_logo_line(struct fb_info *info, int rotate,
-                            const struct linux_logo *logo, int y,
-                            unsigned int n)
-{
-       u32 *palette = NULL, *saved_pseudo_palette = NULL;
-       unsigned char *logo_new = NULL, *logo_rotate = NULL;
-       struct fb_image image;
-
-       /* Return if the frame buffer is not mapped or suspended */
-       if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
-           info->flags & FBINFO_MODULE)
-               return 0;
-
-       image.depth = 8;
-       image.data = logo->data;
-
-       if (fb_logo.needs_cmapreset)
-               fb_set_logocmap(info, logo);
-
-       if (fb_logo.needs_truepalette ||
-           fb_logo.needs_directpalette) {
-               palette = kmalloc(256 * 4, GFP_KERNEL);
-               if (palette == NULL)
-                       return 0;
-
-               if (fb_logo.needs_truepalette)
-                       fb_set_logo_truepalette(info, logo, palette);
-               else
-                       fb_set_logo_directpalette(info, logo, palette);
-
-               saved_pseudo_palette = info->pseudo_palette;
-               info->pseudo_palette = palette;
-       }
-
-       if (fb_logo.depth <= 4) {
-               logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
-               if (logo_new == NULL) {
-                       kfree(palette);
-                       if (saved_pseudo_palette)
-                               info->pseudo_palette = saved_pseudo_palette;
-                       return 0;
-               }
-               image.data = logo_new;
-               fb_set_logo(info, logo, logo_new, fb_logo.depth);
-       }
-
-       image.dx = 0;
-       image.dy = y;
-       image.width = logo->width;
-       image.height = logo->height;
-
-       if (rotate) {
-               logo_rotate = kmalloc(logo->width *
-                                     logo->height, GFP_KERNEL);
-               if (logo_rotate)
-                       fb_rotate_logo(info, logo_rotate, &image, rotate);
-       }
-
-       fb_do_show_logo(info, &image, rotate, n);
-
-       kfree(palette);
-       if (saved_pseudo_palette != NULL)
-               info->pseudo_palette = saved_pseudo_palette;
-       kfree(logo_new);
-       kfree(logo_rotate);
-       return logo->height;
-}
-
-
-#ifdef CONFIG_FB_LOGO_EXTRA
-
-#define FB_LOGO_EX_NUM_MAX 10
-static struct logo_data_extra {
-       const struct linux_logo *logo;
-       unsigned int n;
-} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
-static unsigned int fb_logo_ex_num;
-
-void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
-{
-       if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
-               return;
-
-       fb_logo_ex[fb_logo_ex_num].logo = logo;
-       fb_logo_ex[fb_logo_ex_num].n = n;
-       fb_logo_ex_num++;
-}
-
-static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
-                                 unsigned int yres)
-{
-       unsigned int i;
-
-       /* FIXME: logo_ex supports only truecolor fb. */
-       if (info->fix.visual != FB_VISUAL_TRUECOLOR)
-               fb_logo_ex_num = 0;
-
-       for (i = 0; i < fb_logo_ex_num; i++) {
-               if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
-                       fb_logo_ex[i].logo = NULL;
-                       continue;
-               }
-               height += fb_logo_ex[i].logo->height;
-               if (height > yres) {
-                       height -= fb_logo_ex[i].logo->height;
-                       fb_logo_ex_num = i;
-                       break;
-               }
-       }
-       return height;
-}
-
-static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
-{
-       unsigned int i;
-
-       for (i = 0; i < fb_logo_ex_num; i++)
-               y += fb_show_logo_line(info, rotate,
-                                      fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
-
-       return y;
-}
-
-#else /* !CONFIG_FB_LOGO_EXTRA */
-
-static inline int fb_prepare_extra_logos(struct fb_info *info,
-                                        unsigned int height,
-                                        unsigned int yres)
-{
-       return height;
-}
-
-static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
-{
-       return y;
-}
-
-#endif /* CONFIG_FB_LOGO_EXTRA */
-
-
-int fb_prepare_logo(struct fb_info *info, int rotate)
-{
-       int depth = fb_get_color_depth(&info->var, &info->fix);
-       unsigned int yres;
-
-       memset(&fb_logo, 0, sizeof(struct logo_data));
-
-       if (info->flags & FBINFO_MISC_TILEBLITTING ||
-           info->flags & FBINFO_MODULE)
-               return 0;
-
-       if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-               depth = info->var.blue.length;
-               if (info->var.red.length < depth)
-                       depth = info->var.red.length;
-               if (info->var.green.length < depth)
-                       depth = info->var.green.length;
-       }
-
-       if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
-               /* assume console colormap */
-               depth = 4;
-       }
-
-       /* Return if no suitable logo was found */
-       fb_logo.logo = fb_find_logo(depth);
-
-       if (!fb_logo.logo) {
-               return 0;
-       }
-
-       if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
-               yres = info->var.yres;
-       else
-               yres = info->var.xres;
-
-       if (fb_logo.logo->height > yres) {
-               fb_logo.logo = NULL;
-               return 0;
-       }
-
-       /* What depth we asked for might be different from what we get */
-       if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
-               fb_logo.depth = 8;
-       else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
-               fb_logo.depth = 4;
-       else
-               fb_logo.depth = 1;
-
-
-       if (fb_logo.depth > 4 && depth > 4) {
-               switch (info->fix.visual) {
-               case FB_VISUAL_TRUECOLOR:
-                       fb_logo.needs_truepalette = 1;
-                       break;
-               case FB_VISUAL_DIRECTCOLOR:
-                       fb_logo.needs_directpalette = 1;
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               case FB_VISUAL_PSEUDOCOLOR:
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               }
-       }
-
-       return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
-}
-
-int fb_show_logo(struct fb_info *info, int rotate)
-{
-       int y;
-
-       y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
-                             num_online_cpus());
-       y = fb_show_extra_logos(info, y, rotate);
-
-       return y;
-}
-#else
-int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
-int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
-#endif /* CONFIG_LOGO */
-EXPORT_SYMBOL(fb_show_logo);
-
-static void *fb_seq_start(struct seq_file *m, loff_t *pos)
-{
-       mutex_lock(&registration_lock);
-       return (*pos < FB_MAX) ? pos : NULL;
-}
-
-static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return (*pos < FB_MAX) ? pos : NULL;
-}
-
-static void fb_seq_stop(struct seq_file *m, void *v)
-{
-       mutex_unlock(&registration_lock);
-}
-
-static int fb_seq_show(struct seq_file *m, void *v)
-{
-       int i = *(loff_t *)v;
-       struct fb_info *fi = registered_fb[i];
-
-       if (fi)
-               seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
-       return 0;
-}
-
-static const struct seq_operations proc_fb_seq_ops = {
-       .start  = fb_seq_start,
-       .next   = fb_seq_next,
-       .stop   = fb_seq_stop,
-       .show   = fb_seq_show,
-};
-
-static int proc_fb_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &proc_fb_seq_ops);
-}
-
-static const struct file_operations fb_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_fb_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-/*
- * We hold a reference to the fb_info in file->private_data,
- * but if the current registered fb has changed, we don't
- * actually want to use it.
- *
- * So look up the fb_info using the inode minor number,
- * and just verify it against the reference we have.
- */
-static struct fb_info *file_fb_info(struct file *file)
-{
-       struct inode *inode = file_inode(file);
-       int fbidx = iminor(inode);
-       struct fb_info *info = registered_fb[fbidx];
-
-       if (info != file->private_data)
-               info = NULL;
-       return info;
-}
-
-static ssize_t
-fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-       unsigned long p = *ppos;
-       struct fb_info *info = file_fb_info(file);
-       u8 *buffer, *dst;
-       u8 __iomem *src;
-       int c, cnt = 0, err = 0;
-       unsigned long total_size;
-
-       if (!info || ! info->screen_base)
-               return -ENODEV;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return -EPERM;
-
-       if (info->fbops->fb_read)
-               return info->fbops->fb_read(info, buf, count, ppos);
-       
-       total_size = info->screen_size;
-
-       if (total_size == 0)
-               total_size = info->fix.smem_len;
-
-       if (p >= total_size)
-               return 0;
-
-       if (count >= total_size)
-               count = total_size;
-
-       if (count + p > total_size)
-               count = total_size - p;
-
-       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
-                        GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       src = (u8 __iomem *) (info->screen_base + p);
-
-       if (info->fbops->fb_sync)
-               info->fbops->fb_sync(info);
-
-       while (count) {
-               c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               dst = buffer;
-               fb_memcpy_fromfb(dst, src, c);
-               dst += c;
-               src += c;
-
-               if (copy_to_user(buf, buffer, c)) {
-                       err = -EFAULT;
-                       break;
-               }
-               *ppos += c;
-               buf += c;
-               cnt += c;
-               count -= c;
-       }
-
-       kfree(buffer);
-
-       return (err) ? err : cnt;
-}
-
-static ssize_t
-fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-       unsigned long p = *ppos;
-       struct fb_info *info = file_fb_info(file);
-       u8 *buffer, *src;
-       u8 __iomem *dst;
-       int c, cnt = 0, err = 0;
-       unsigned long total_size;
-
-       if (!info || !info->screen_base)
-               return -ENODEV;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return -EPERM;
-
-       if (info->fbops->fb_write)
-               return info->fbops->fb_write(info, buf, count, ppos);
-       
-       total_size = info->screen_size;
-
-       if (total_size == 0)
-               total_size = info->fix.smem_len;
-
-       if (p > total_size)
-               return -EFBIG;
-
-       if (count > total_size) {
-               err = -EFBIG;
-               count = total_size;
-       }
-
-       if (count + p > total_size) {
-               if (!err)
-                       err = -ENOSPC;
-
-               count = total_size - p;
-       }
-
-       buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
-                        GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       dst = (u8 __iomem *) (info->screen_base + p);
-
-       if (info->fbops->fb_sync)
-               info->fbops->fb_sync(info);
-
-       while (count) {
-               c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               src = buffer;
-
-               if (copy_from_user(src, buf, c)) {
-                       err = -EFAULT;
-                       break;
-               }
-
-               fb_memcpy_tofb(dst, src, c);
-               dst += c;
-               src += c;
-               *ppos += c;
-               buf += c;
-               cnt += c;
-               count -= c;
-       }
-
-       kfree(buffer);
-
-       return (cnt) ? cnt : err;
-}
-
-int
-fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
-{
-       struct fb_fix_screeninfo *fix = &info->fix;
-       unsigned int yres = info->var.yres;
-       int err = 0;
-
-       if (var->yoffset > 0) {
-               if (var->vmode & FB_VMODE_YWRAP) {
-                       if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
-                               err = -EINVAL;
-                       else
-                               yres = 0;
-               } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
-                       err = -EINVAL;
-       }
-
-       if (var->xoffset > 0 && (!fix->xpanstep ||
-                                (var->xoffset % fix->xpanstep)))
-               err = -EINVAL;
-
-       if (err || !info->fbops->fb_pan_display ||
-           var->yoffset > info->var.yres_virtual - yres ||
-           var->xoffset > info->var.xres_virtual - info->var.xres)
-               return -EINVAL;
-
-       if ((err = info->fbops->fb_pan_display(var, info)))
-               return err;
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-       if (var->vmode & FB_VMODE_YWRAP)
-               info->var.vmode |= FB_VMODE_YWRAP;
-       else
-               info->var.vmode &= ~FB_VMODE_YWRAP;
-       return 0;
-}
-EXPORT_SYMBOL(fb_pan_display);
-
-static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
-                        u32 activate)
-{
-       struct fb_event event;
-       struct fb_blit_caps caps, fbcaps;
-       int err = 0;
-
-       memset(&caps, 0, sizeof(caps));
-       memset(&fbcaps, 0, sizeof(fbcaps));
-       caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
-       event.info = info;
-       event.data = &caps;
-       fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
-       info->fbops->fb_get_caps(info, &fbcaps, var);
-
-       if (((fbcaps.x ^ caps.x) & caps.x) ||
-           ((fbcaps.y ^ caps.y) & caps.y) ||
-           (fbcaps.len < caps.len))
-               err = -EINVAL;
-
-       return err;
-}
-
-int
-fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
-{
-       int flags = info->flags;
-       int ret = 0;
-
-       if (var->activate & FB_ACTIVATE_INV_MODE) {
-               struct fb_videomode mode1, mode2;
-
-               fb_var_to_videomode(&mode1, var);
-               fb_var_to_videomode(&mode2, &info->var);
-               /* make sure we don't delete the videomode of current var */
-               ret = fb_mode_is_equal(&mode1, &mode2);
-
-               if (!ret) {
-                   struct fb_event event;
-
-                   event.info = info;
-                   event.data = &mode1;
-                   ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
-               }
-
-               if (!ret)
-                   fb_delete_videomode(&mode1, &info->modelist);
-
-
-               ret = (ret) ? -EINVAL : 0;
-               goto done;
-       }
-
-       if ((var->activate & FB_ACTIVATE_FORCE) ||
-           memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
-               u32 activate = var->activate;
-
-               /* When using FOURCC mode, make sure the red, green, blue and
-                * transp fields are set to 0.
-                */
-               if ((info->fix.capabilities & FB_CAP_FOURCC) &&
-                   var->grayscale > 1) {
-                       if (var->red.offset     || var->green.offset    ||
-                           var->blue.offset    || var->transp.offset   ||
-                           var->red.length     || var->green.length    ||
-                           var->blue.length    || var->transp.length   ||
-                           var->red.msb_right  || var->green.msb_right ||
-                           var->blue.msb_right || var->transp.msb_right)
-                               return -EINVAL;
-               }
-
-               if (!info->fbops->fb_check_var) {
-                       *var = info->var;
-                       goto done;
-               }
-
-               ret = info->fbops->fb_check_var(var, info);
-
-               if (ret)
-                       goto done;
-
-               if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-                       struct fb_var_screeninfo old_var;
-                       struct fb_videomode mode;
-
-                       if (info->fbops->fb_get_caps) {
-                               ret = fb_check_caps(info, var, activate);
-
-                               if (ret)
-                                       goto done;
-                       }
-
-                       old_var = info->var;
-                       info->var = *var;
-
-                       if (info->fbops->fb_set_par) {
-                               ret = info->fbops->fb_set_par(info);
-
-                               if (ret) {
-                                       info->var = old_var;
-                                       printk(KERN_WARNING "detected "
-                                               "fb_set_par error, "
-                                               "error code: %d\n", ret);
-                                       goto done;
-                               }
-                       }
-
-                       fb_pan_display(info, &info->var);
-                       fb_set_cmap(&info->cmap, info);
-                       fb_var_to_videomode(&mode, &info->var);
-
-                       if (info->modelist.prev && info->modelist.next &&
-                           !list_empty(&info->modelist))
-                               ret = fb_add_videomode(&mode, &info->modelist);
-
-                       if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
-                               struct fb_event event;
-                               int evnt = (activate & FB_ACTIVATE_ALL) ?
-                                       FB_EVENT_MODE_CHANGE_ALL :
-                                       FB_EVENT_MODE_CHANGE;
-
-                               info->flags &= ~FBINFO_MISC_USEREVENT;
-                               event.info = info;
-                               event.data = &mode;
-                               fb_notifier_call_chain(evnt, &event);
-                       }
-               }
-       }
-
- done:
-       return ret;
-}
-EXPORT_SYMBOL(fb_set_var);
-
-int
-fb_blank(struct fb_info *info, int blank)
-{      
-       struct fb_event event;
-       int ret = -EINVAL, early_ret;
-
-       if (blank > FB_BLANK_POWERDOWN)
-               blank = FB_BLANK_POWERDOWN;
-
-       event.info = info;
-       event.data = &blank;
-
-       early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
-
-       if (info->fbops->fb_blank)
-               ret = info->fbops->fb_blank(blank, info);
-
-       if (!ret)
-               fb_notifier_call_chain(FB_EVENT_BLANK, &event);
-       else {
-               /*
-                * if fb_blank is failed then revert effects of
-                * the early blank event.
-                */
-               if (!early_ret)
-                       fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(fb_blank);
-
-static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
-                       unsigned long arg)
-{
-       struct fb_ops *fb;
-       struct fb_var_screeninfo var;
-       struct fb_fix_screeninfo fix;
-       struct fb_con2fbmap con2fb;
-       struct fb_cmap cmap_from;
-       struct fb_cmap_user cmap;
-       struct fb_event event;
-       void __user *argp = (void __user *)arg;
-       long ret = 0;
-
-       switch (cmd) {
-       case FBIOGET_VSCREENINFO:
-               if (!lock_fb_info(info))
-                       return -ENODEV;
-               var = info->var;
-               unlock_fb_info(info);
-
-               ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
-               break;
-       case FBIOPUT_VSCREENINFO:
-               if (copy_from_user(&var, argp, sizeof(var)))
-                       return -EFAULT;
-               console_lock();
-               if (!lock_fb_info(info)) {
-                       console_unlock();
-                       return -ENODEV;
-               }
-               info->flags |= FBINFO_MISC_USEREVENT;
-               ret = fb_set_var(info, &var);
-               info->flags &= ~FBINFO_MISC_USEREVENT;
-               unlock_fb_info(info);
-               console_unlock();
-               if (!ret && copy_to_user(argp, &var, sizeof(var)))
-                       ret = -EFAULT;
-               break;
-       case FBIOGET_FSCREENINFO:
-               if (!lock_fb_info(info))
-                       return -ENODEV;
-               fix = info->fix;
-               unlock_fb_info(info);
-
-               ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
-               break;
-       case FBIOPUTCMAP:
-               if (copy_from_user(&cmap, argp, sizeof(cmap)))
-                       return -EFAULT;
-               ret = fb_set_user_cmap(&cmap, info);
-               break;
-       case FBIOGETCMAP:
-               if (copy_from_user(&cmap, argp, sizeof(cmap)))
-                       return -EFAULT;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
-               cmap_from = info->cmap;
-               unlock_fb_info(info);
-               ret = fb_cmap_to_user(&cmap_from, &cmap);
-               break;
-       case FBIOPAN_DISPLAY:
-               if (copy_from_user(&var, argp, sizeof(var)))
-                       return -EFAULT;
-               console_lock();
-               if (!lock_fb_info(info)) {
-                       console_unlock();
-                       return -ENODEV;
-               }
-               ret = fb_pan_display(info, &var);
-               unlock_fb_info(info);
-               console_unlock();
-               if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
-                       return -EFAULT;
-               break;
-       case FBIO_CURSOR:
-               ret = -EINVAL;
-               break;
-       case FBIOGET_CON2FBMAP:
-               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
-                       return -EFAULT;
-               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
-                       return -EINVAL;
-               con2fb.framebuffer = -1;
-               event.data = &con2fb;
-               if (!lock_fb_info(info))
-                       return -ENODEV;
-               event.info = info;
-               fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
-               unlock_fb_info(info);
-               ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
-               break;
-       case FBIOPUT_CON2FBMAP:
-               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
-                       return -EFAULT;
-               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
-                       return -EINVAL;
-               if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
-                       return -EINVAL;
-               if (!registered_fb[con2fb.framebuffer])
-                       request_module("fb%d", con2fb.framebuffer);
-               if (!registered_fb[con2fb.framebuffer]) {
-                       ret = -EINVAL;
-                       break;
-               }
-               event.data = &con2fb;
-               console_lock();
-               if (!lock_fb_info(info)) {
-                       console_unlock();
-                       return -ENODEV;
-               }
-               event.info = info;
-               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
-               unlock_fb_info(info);
-               console_unlock();
-               break;
-       case FBIOBLANK:
-               console_lock();
-               if (!lock_fb_info(info)) {
-                       console_unlock();
-                       return -ENODEV;
-               }
-               info->flags |= FBINFO_MISC_USEREVENT;
-               ret = fb_blank(info, arg);
-               info->flags &= ~FBINFO_MISC_USEREVENT;
-               unlock_fb_info(info);
-               console_unlock();
-               break;
-       default:
-               if (!lock_fb_info(info))
-                       return -ENODEV;
-               fb = info->fbops;
-               if (fb->fb_ioctl)
-                       ret = fb->fb_ioctl(info, cmd, arg);
-               else
-                       ret = -ENOTTY;
-               unlock_fb_info(info);
-       }
-       return ret;
-}
-
-static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct fb_info *info = file_fb_info(file);
-
-       if (!info)
-               return -ENODEV;
-       return do_fb_ioctl(info, cmd, arg);
-}
-
-#ifdef CONFIG_COMPAT
-struct fb_fix_screeninfo32 {
-       char                    id[16];
-       compat_caddr_t          smem_start;
-       u32                     smem_len;
-       u32                     type;
-       u32                     type_aux;
-       u32                     visual;
-       u16                     xpanstep;
-       u16                     ypanstep;
-       u16                     ywrapstep;
-       u32                     line_length;
-       compat_caddr_t          mmio_start;
-       u32                     mmio_len;
-       u32                     accel;
-       u16                     reserved[3];
-};
-
-struct fb_cmap32 {
-       u32                     start;
-       u32                     len;
-       compat_caddr_t  red;
-       compat_caddr_t  green;
-       compat_caddr_t  blue;
-       compat_caddr_t  transp;
-};
-
-static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
-                         unsigned long arg)
-{
-       struct fb_cmap_user __user *cmap;
-       struct fb_cmap32 __user *cmap32;
-       __u32 data;
-       int err;
-
-       cmap = compat_alloc_user_space(sizeof(*cmap));
-       cmap32 = compat_ptr(arg);
-
-       if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
-               return -EFAULT;
-
-       if (get_user(data, &cmap32->red) ||
-           put_user(compat_ptr(data), &cmap->red) ||
-           get_user(data, &cmap32->green) ||
-           put_user(compat_ptr(data), &cmap->green) ||
-           get_user(data, &cmap32->blue) ||
-           put_user(compat_ptr(data), &cmap->blue) ||
-           get_user(data, &cmap32->transp) ||
-           put_user(compat_ptr(data), &cmap->transp))
-               return -EFAULT;
-
-       err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
-
-       if (!err) {
-               if (copy_in_user(&cmap32->start,
-                                &cmap->start,
-                                2 * sizeof(__u32)))
-                       err = -EFAULT;
-       }
-       return err;
-}
-
-static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
-                                 struct fb_fix_screeninfo32 __user *fix32)
-{
-       __u32 data;
-       int err;
-
-       err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
-
-       data = (__u32) (unsigned long) fix->smem_start;
-       err |= put_user(data, &fix32->smem_start);
-
-       err |= put_user(fix->smem_len, &fix32->smem_len);
-       err |= put_user(fix->type, &fix32->type);
-       err |= put_user(fix->type_aux, &fix32->type_aux);
-       err |= put_user(fix->visual, &fix32->visual);
-       err |= put_user(fix->xpanstep, &fix32->xpanstep);
-       err |= put_user(fix->ypanstep, &fix32->ypanstep);
-       err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
-       err |= put_user(fix->line_length, &fix32->line_length);
-
-       data = (__u32) (unsigned long) fix->mmio_start;
-       err |= put_user(data, &fix32->mmio_start);
-
-       err |= put_user(fix->mmio_len, &fix32->mmio_len);
-       err |= put_user(fix->accel, &fix32->accel);
-       err |= copy_to_user(fix32->reserved, fix->reserved,
-                           sizeof(fix->reserved));
-
-       if (err)
-               return -EFAULT;
-       return 0;
-}
-
-static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
-                             unsigned long arg)
-{
-       mm_segment_t old_fs;
-       struct fb_fix_screeninfo fix;
-       struct fb_fix_screeninfo32 __user *fix32;
-       int err;
-
-       fix32 = compat_ptr(arg);
-
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
-       set_fs(old_fs);
-
-       if (!err)
-               err = do_fscreeninfo_to_user(&fix, fix32);
-
-       return err;
-}
-
-static long fb_compat_ioctl(struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       struct fb_info *info = file_fb_info(file);
-       struct fb_ops *fb;
-       long ret = -ENOIOCTLCMD;
-
-       if (!info)
-               return -ENODEV;
-       fb = info->fbops;
-       switch(cmd) {
-       case FBIOGET_VSCREENINFO:
-       case FBIOPUT_VSCREENINFO:
-       case FBIOPAN_DISPLAY:
-       case FBIOGET_CON2FBMAP:
-       case FBIOPUT_CON2FBMAP:
-               arg = (unsigned long) compat_ptr(arg);
-       case FBIOBLANK:
-               ret = do_fb_ioctl(info, cmd, arg);
-               break;
-
-       case FBIOGET_FSCREENINFO:
-               ret = fb_get_fscreeninfo(info, cmd, arg);
-               break;
-
-       case FBIOGETCMAP:
-       case FBIOPUTCMAP:
-               ret = fb_getput_cmap(info, cmd, arg);
-               break;
-
-       default:
-               if (fb->fb_compat_ioctl)
-                       ret = fb->fb_compat_ioctl(info, cmd, arg);
-               break;
-       }
-       return ret;
-}
-#endif
-
-static int
-fb_mmap(struct file *file, struct vm_area_struct * vma)
-{
-       struct fb_info *info = file_fb_info(file);
-       struct fb_ops *fb;
-       unsigned long mmio_pgoff;
-       unsigned long start;
-       u32 len;
-
-       if (!info)
-               return -ENODEV;
-       fb = info->fbops;
-       if (!fb)
-               return -ENODEV;
-       mutex_lock(&info->mm_lock);
-       if (fb->fb_mmap) {
-               int res;
-               res = fb->fb_mmap(info, vma);
-               mutex_unlock(&info->mm_lock);
-               return res;
-       }
-
-       /*
-        * Ugh. This can be either the frame buffer mapping, or
-        * if pgoff points past it, the mmio mapping.
-        */
-       start = info->fix.smem_start;
-       len = info->fix.smem_len;
-       mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
-       if (vma->vm_pgoff >= mmio_pgoff) {
-               if (info->var.accel_flags) {
-                       mutex_unlock(&info->mm_lock);
-                       return -EINVAL;
-               }
-
-               vma->vm_pgoff -= mmio_pgoff;
-               start = info->fix.mmio_start;
-               len = info->fix.mmio_len;
-       }
-       mutex_unlock(&info->mm_lock);
-
-       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
-       fb_pgprotect(file, vma, start);
-
-       return vm_iomap_memory(vma, start, len);
-}
-
-static int
-fb_open(struct inode *inode, struct file *file)
-__acquires(&info->lock)
-__releases(&info->lock)
-{
-       int fbidx = iminor(inode);
-       struct fb_info *info;
-       int res = 0;
-
-       info = get_fb_info(fbidx);
-       if (!info) {
-               request_module("fb%d", fbidx);
-               info = get_fb_info(fbidx);
-               if (!info)
-                       return -ENODEV;
-       }
-       if (IS_ERR(info))
-               return PTR_ERR(info);
-
-       mutex_lock(&info->lock);
-       if (!try_module_get(info->fbops->owner)) {
-               res = -ENODEV;
-               goto out;
-       }
-       file->private_data = info;
-       if (info->fbops->fb_open) {
-               res = info->fbops->fb_open(info,1);
-               if (res)
-                       module_put(info->fbops->owner);
-       }
-#ifdef CONFIG_FB_DEFERRED_IO
-       if (info->fbdefio)
-               fb_deferred_io_open(info, inode, file);
-#endif
-out:
-       mutex_unlock(&info->lock);
-       if (res)
-               put_fb_info(info);
-       return res;
-}
-
-static int 
-fb_release(struct inode *inode, struct file *file)
-__acquires(&info->lock)
-__releases(&info->lock)
-{
-       struct fb_info * const info = file->private_data;
-
-       mutex_lock(&info->lock);
-       if (info->fbops->fb_release)
-               info->fbops->fb_release(info,1);
-       module_put(info->fbops->owner);
-       mutex_unlock(&info->lock);
-       put_fb_info(info);
-       return 0;
-}
-
-static const struct file_operations fb_fops = {
-       .owner =        THIS_MODULE,
-       .read =         fb_read,
-       .write =        fb_write,
-       .unlocked_ioctl = fb_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = fb_compat_ioctl,
-#endif
-       .mmap =         fb_mmap,
-       .open =         fb_open,
-       .release =      fb_release,
-#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
-       .get_unmapped_area = get_fb_unmapped_area,
-#endif
-#ifdef CONFIG_FB_DEFERRED_IO
-       .fsync =        fb_deferred_io_fsync,
-#endif
-       .llseek =       default_llseek,
-};
-
-struct class *fb_class;
-EXPORT_SYMBOL(fb_class);
-
-static int fb_check_foreignness(struct fb_info *fi)
-{
-       const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
-
-       fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
-
-#ifdef __BIG_ENDIAN
-       fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
-#else
-       fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
-#endif /* __BIG_ENDIAN */
-
-       if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
-               pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
-                      "support this framebuffer\n", fi->fix.id);
-               return -ENOSYS;
-       } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
-               pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
-                      "support this framebuffer\n", fi->fix.id);
-               return -ENOSYS;
-       }
-
-       return 0;
-}
-
-static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
-{
-       /* is the generic aperture base the same as the HW one */
-       if (gen->base == hw->base)
-               return true;
-       /* is the generic aperture base inside the hw base->hw base+size */
-       if (gen->base > hw->base && gen->base < hw->base + hw->size)
-               return true;
-       return false;
-}
-
-static bool fb_do_apertures_overlap(struct apertures_struct *gena,
-                                   struct apertures_struct *hwa)
-{
-       int i, j;
-       if (!hwa || !gena)
-               return false;
-
-       for (i = 0; i < hwa->count; ++i) {
-               struct aperture *h = &hwa->ranges[i];
-               for (j = 0; j < gena->count; ++j) {
-                       struct aperture *g = &gena->ranges[j];
-                       printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
-                               (unsigned long long)g->base,
-                               (unsigned long long)g->size,
-                               (unsigned long long)h->base,
-                               (unsigned long long)h->size);
-                       if (apertures_overlap(g, h))
-                               return true;
-               }
-       }
-
-       return false;
-}
-
-static int do_unregister_framebuffer(struct fb_info *fb_info);
-
-#define VGA_FB_PHYS 0xA0000
-static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
-                                             const char *name, bool primary)
-{
-       int i, ret;
-
-       /* check all firmware fbs and kick off if the base addr overlaps */
-       for (i = 0 ; i < FB_MAX; i++) {
-               struct apertures_struct *gen_aper;
-               if (!registered_fb[i])
-                       continue;
-
-               if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
-                       continue;
-
-               gen_aper = registered_fb[i]->apertures;
-               if (fb_do_apertures_overlap(gen_aper, a) ||
-                       (primary && gen_aper && gen_aper->count &&
-                        gen_aper->ranges[0].base == VGA_FB_PHYS)) {
-
-                       printk(KERN_INFO "fb: switching to %s from %s\n",
-                              name, registered_fb[i]->fix.id);
-                       ret = do_unregister_framebuffer(registered_fb[i]);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int do_register_framebuffer(struct fb_info *fb_info)
-{
-       int i, ret;
-       struct fb_event event;
-       struct fb_videomode mode;
-
-       if (fb_check_foreignness(fb_info))
-               return -ENOSYS;
-
-       ret = do_remove_conflicting_framebuffers(fb_info->apertures,
-                                                fb_info->fix.id,
-                                                fb_is_primary_device(fb_info));
-       if (ret)
-               return ret;
-
-       if (num_registered_fb == FB_MAX)
-               return -ENXIO;
-
-       num_registered_fb++;
-       for (i = 0 ; i < FB_MAX; i++)
-               if (!registered_fb[i])
-                       break;
-       fb_info->node = i;
-       atomic_set(&fb_info->count, 1);
-       mutex_init(&fb_info->lock);
-       mutex_init(&fb_info->mm_lock);
-
-       fb_info->dev = device_create(fb_class, fb_info->device,
-                                    MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
-       if (IS_ERR(fb_info->dev)) {
-               /* Not fatal */
-               printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
-               fb_info->dev = NULL;
-       } else
-               fb_init_device(fb_info);
-
-       if (fb_info->pixmap.addr == NULL) {
-               fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
-               if (fb_info->pixmap.addr) {
-                       fb_info->pixmap.size = FBPIXMAPSIZE;
-                       fb_info->pixmap.buf_align = 1;
-                       fb_info->pixmap.scan_align = 1;
-                       fb_info->pixmap.access_align = 32;
-                       fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
-               }
-       }       
-       fb_info->pixmap.offset = 0;
-
-       if (!fb_info->pixmap.blit_x)
-               fb_info->pixmap.blit_x = ~(u32)0;
-
-       if (!fb_info->pixmap.blit_y)
-               fb_info->pixmap.blit_y = ~(u32)0;
-
-       if (!fb_info->modelist.prev || !fb_info->modelist.next)
-               INIT_LIST_HEAD(&fb_info->modelist);
-
-       if (fb_info->skip_vt_switch)
-               pm_vt_switch_required(fb_info->dev, false);
-       else
-               pm_vt_switch_required(fb_info->dev, true);
-
-       fb_var_to_videomode(&mode, &fb_info->var);
-       fb_add_videomode(&mode, &fb_info->modelist);
-       registered_fb[i] = fb_info;
-
-       event.info = fb_info;
-       console_lock();
-       if (!lock_fb_info(fb_info)) {
-               console_unlock();
-               return -ENODEV;
-       }
-
-       fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
-       unlock_fb_info(fb_info);
-       console_unlock();
-       return 0;
-}
-
-static int do_unregister_framebuffer(struct fb_info *fb_info)
-{
-       struct fb_event event;
-       int i, ret = 0;
-
-       i = fb_info->node;
-       if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
-               return -EINVAL;
-
-       console_lock();
-       if (!lock_fb_info(fb_info)) {
-               console_unlock();
-               return -ENODEV;
-       }
-
-       event.info = fb_info;
-       ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
-       unlock_fb_info(fb_info);
-       console_unlock();
-
-       if (ret)
-               return -EINVAL;
-
-       pm_vt_switch_unregister(fb_info->dev);
-
-       unlink_framebuffer(fb_info);
-       if (fb_info->pixmap.addr &&
-           (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
-               kfree(fb_info->pixmap.addr);
-       fb_destroy_modelist(&fb_info->modelist);
-       registered_fb[i] = NULL;
-       num_registered_fb--;
-       fb_cleanup_device(fb_info);
-       event.info = fb_info;
-       console_lock();
-       fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
-       console_unlock();
-
-       /* this may free fb info */
-       put_fb_info(fb_info);
-       return 0;
-}
-
-int unlink_framebuffer(struct fb_info *fb_info)
-{
-       int i;
-
-       i = fb_info->node;
-       if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
-               return -EINVAL;
-
-       if (fb_info->dev) {
-               device_destroy(fb_class, MKDEV(FB_MAJOR, i));
-               fb_info->dev = NULL;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(unlink_framebuffer);
-
-int remove_conflicting_framebuffers(struct apertures_struct *a,
-                                   const char *name, bool primary)
-{
-       int ret;
-
-       mutex_lock(&registration_lock);
-       ret = do_remove_conflicting_framebuffers(a, name, primary);
-       mutex_unlock(&registration_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(remove_conflicting_framebuffers);
-
-/**
- *     register_framebuffer - registers a frame buffer device
- *     @fb_info: frame buffer info structure
- *
- *     Registers a frame buffer device @fb_info.
- *
- *     Returns negative errno on error, or zero for success.
- *
- */
-int
-register_framebuffer(struct fb_info *fb_info)
-{
-       int ret;
-
-       mutex_lock(&registration_lock);
-       ret = do_register_framebuffer(fb_info);
-       mutex_unlock(&registration_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(register_framebuffer);
-
-/**
- *     unregister_framebuffer - releases a frame buffer device
- *     @fb_info: frame buffer info structure
- *
- *     Unregisters a frame buffer device @fb_info.
- *
- *     Returns negative errno on error, or zero for success.
- *
- *      This function will also notify the framebuffer console
- *      to release the driver.
- *
- *      This is meant to be called within a driver's module_exit()
- *      function. If this is called outside module_exit(), ensure
- *      that the driver implements fb_open() and fb_release() to
- *      check that no processes are using the device.
- */
-int
-unregister_framebuffer(struct fb_info *fb_info)
-{
-       int ret;
-
-       mutex_lock(&registration_lock);
-       ret = do_unregister_framebuffer(fb_info);
-       mutex_unlock(&registration_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(unregister_framebuffer);
-
-/**
- *     fb_set_suspend - low level driver signals suspend
- *     @info: framebuffer affected
- *     @state: 0 = resuming, !=0 = suspending
- *
- *     This is meant to be used by low level drivers to
- *     signal suspend/resume to the core & clients.
- *     It must be called with the console semaphore held
- */
-void fb_set_suspend(struct fb_info *info, int state)
-{
-       struct fb_event event;
-
-       event.info = info;
-       if (state) {
-               fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
-               info->state = FBINFO_STATE_SUSPENDED;
-       } else {
-               info->state = FBINFO_STATE_RUNNING;
-               fb_notifier_call_chain(FB_EVENT_RESUME, &event);
-       }
-}
-EXPORT_SYMBOL(fb_set_suspend);
-
-/**
- *     fbmem_init - init frame buffer subsystem
- *
- *     Initialize the frame buffer subsystem.
- *
- *     NOTE: This function is _only_ to be called by drivers/char/mem.c.
- *
- */
-
-static int __init
-fbmem_init(void)
-{
-       proc_create("fb", 0, NULL, &fb_proc_fops);
-
-       if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
-               printk("unable to get major %d for fb devs\n", FB_MAJOR);
-
-       fb_class = class_create(THIS_MODULE, "graphics");
-       if (IS_ERR(fb_class)) {
-               printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
-               fb_class = NULL;
-       }
-       return 0;
-}
-
-#ifdef MODULE
-module_init(fbmem_init);
-static void __exit
-fbmem_exit(void)
-{
-       remove_proc_entry("fb", NULL);
-       class_destroy(fb_class);
-       unregister_chrdev(FB_MAJOR, "fb");
-}
-
-module_exit(fbmem_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Framebuffer base");
-#else
-subsys_initcall(fbmem_init);
-#endif
-
-int fb_new_modelist(struct fb_info *info)
-{
-       struct fb_event event;
-       struct fb_var_screeninfo var = info->var;
-       struct list_head *pos, *n;
-       struct fb_modelist *modelist;
-       struct fb_videomode *m, mode;
-       int err = 1;
-
-       list_for_each_safe(pos, n, &info->modelist) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               m = &modelist->mode;
-               fb_videomode_to_var(&var, m);
-               var.activate = FB_ACTIVATE_TEST;
-               err = fb_set_var(info, &var);
-               fb_var_to_videomode(&mode, &var);
-               if (err || !fb_mode_is_equal(m, &mode)) {
-                       list_del(pos);
-                       kfree(pos);
-               }
-       }
-
-       err = 1;
-
-       if (!list_empty(&info->modelist)) {
-               event.info = info;
-               err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
-       }
-
-       return err;
-}
-
-static char *video_options[FB_MAX] __read_mostly;
-static int ofonly __read_mostly;
-
-/**
- * fb_get_options - get kernel boot parameters
- * @name:   framebuffer name as it would appear in
- *          the boot parameter line
- *          (video=<name>:<options>)
- * @option: the option will be stored here
- *
- * NOTE: Needed to maintain backwards compatibility
- */
-int fb_get_options(const char *name, char **option)
-{
-       char *opt, *options = NULL;
-       int retval = 0;
-       int name_len = strlen(name), i;
-
-       if (name_len && ofonly && strncmp(name, "offb", 4))
-               retval = 1;
-
-       if (name_len && !retval) {
-               for (i = 0; i < FB_MAX; i++) {
-                       if (video_options[i] == NULL)
-                               continue;
-                       if (!video_options[i][0])
-                               continue;
-                       opt = video_options[i];
-                       if (!strncmp(name, opt, name_len) &&
-                           opt[name_len] == ':')
-                               options = opt + name_len + 1;
-               }
-       }
-       /* No match, pass global option */
-       if (!options && option && fb_mode_option)
-               options = kstrdup(fb_mode_option, GFP_KERNEL);
-       if (options && !strncmp(options, "off", 3))
-               retval = 1;
-
-       if (option)
-               *option = options;
-
-       return retval;
-}
-EXPORT_SYMBOL(fb_get_options);
-
-#ifndef MODULE
-/**
- *     video_setup - process command line options
- *     @options: string of options
- *
- *     Process command line options for frame buffer subsystem.
- *
- *     NOTE: This function is a __setup and __init function.
- *            It only stores the options.  Drivers have to call
- *            fb_get_options() as necessary.
- *
- *     Returns zero.
- *
- */
-static int __init video_setup(char *options)
-{
-       int i, global = 0;
-
-       if (!options || !*options)
-               global = 1;
-
-       if (!global && !strncmp(options, "ofonly", 6)) {
-               ofonly = 1;
-               global = 1;
-       }
-
-       if (!global && !strchr(options, ':')) {
-               fb_mode_option = options;
-               global = 1;
-       }
-
-       if (!global) {
-               for (i = 0; i < FB_MAX; i++) {
-                       if (video_options[i] == NULL) {
-                               video_options[i] = options;
-                               break;
-                       }
-
-               }
-       }
-
-       return 1;
-}
-__setup("video=", video_setup);
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/fbmon.c b/drivers/video/fbdev/fbmon.c
deleted file mode 100644 (file)
index 6103fa6..0000000
+++ /dev/null
@@ -1,1592 +0,0 @@
-/*
- * linux/drivers/video/fbmon.c
- *
- * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
- *
- * Credits:
- *
- * The EDID Parser is a conglomeration from the following sources:
- *
- *   1. SciTech SNAP Graphics Architecture
- *      Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
- *
- *   2. XFree86 4.3.0, interpret_edid.c
- *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- *
- *   3. John Fremlin <vii@users.sourceforge.net> and
- *      Ani Joshi <ajoshi@unixbox.com>
- *
- * Generalized Timing Formula is derived from:
- *
- *      GTF Spreadsheet by Andy Morrish (1/5/97)
- *      available at http://www.vesa.org
- *
- * 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.
- *
- */
-#include <linux/fb.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <video/edid.h>
-#include <video/of_videomode.h>
-#include <video/videomode.h>
-#ifdef CONFIG_PPC_OF
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif
-#include "edid.h"
-
-/*
- * EDID parser
- */
-
-#undef DEBUG  /* define this for verbose EDID parsing output */
-
-#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(fmt,## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#define FBMON_FIX_HEADER  1
-#define FBMON_FIX_INPUT   2
-#define FBMON_FIX_TIMINGS 3
-
-#ifdef CONFIG_FB_MODE_HELPERS
-struct broken_edid {
-       u8  manufacturer[4];
-       u32 model;
-       u32 fix;
-};
-
-static const struct broken_edid brokendb[] = {
-       /* DEC FR-PCXAV-YZ */
-       {
-               .manufacturer = "DEC",
-               .model        = 0x073a,
-               .fix          = FBMON_FIX_HEADER,
-       },
-       /* ViewSonic PF775a */
-       {
-               .manufacturer = "VSC",
-               .model        = 0x5a44,
-               .fix          = FBMON_FIX_INPUT,
-       },
-       /* Sharp UXGA? */
-       {
-               .manufacturer = "SHP",
-               .model        = 0x138e,
-               .fix          = FBMON_FIX_TIMINGS,
-       },
-};
-
-static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
-       0xff, 0xff, 0xff, 0x00
-};
-
-static void copy_string(unsigned char *c, unsigned char *s)
-{
-  int i;
-  c = c + 5;
-  for (i = 0; (i < 13 && *c != 0x0A); i++)
-    *(s++) = *(c++);
-  *s = 0;
-  while (i-- && (*--s == 0x20)) *s = 0;
-}
-
-static int edid_is_serial_block(unsigned char *block)
-{
-       if ((block[0] == 0x00) && (block[1] == 0x00) &&
-           (block[2] == 0x00) && (block[3] == 0xff) &&
-           (block[4] == 0x00))
-               return 1;
-       else
-               return 0;
-}
-
-static int edid_is_ascii_block(unsigned char *block)
-{
-       if ((block[0] == 0x00) && (block[1] == 0x00) &&
-           (block[2] == 0x00) && (block[3] == 0xfe) &&
-           (block[4] == 0x00))
-               return 1;
-       else
-               return 0;
-}
-
-static int edid_is_limits_block(unsigned char *block)
-{
-       if ((block[0] == 0x00) && (block[1] == 0x00) &&
-           (block[2] == 0x00) && (block[3] == 0xfd) &&
-           (block[4] == 0x00))
-               return 1;
-       else
-               return 0;
-}
-
-static int edid_is_monitor_block(unsigned char *block)
-{
-       if ((block[0] == 0x00) && (block[1] == 0x00) &&
-           (block[2] == 0x00) && (block[3] == 0xfc) &&
-           (block[4] == 0x00))
-               return 1;
-       else
-               return 0;
-}
-
-static int edid_is_timing_block(unsigned char *block)
-{
-       if ((block[0] != 0x00) || (block[1] != 0x00) ||
-           (block[2] != 0x00) || (block[4] != 0x00))
-               return 1;
-       else
-               return 0;
-}
-
-static int check_edid(unsigned char *edid)
-{
-       unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
-       unsigned char *b;
-       u32 model;
-       int i, fix = 0, ret = 0;
-
-       manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
-       manufacturer[1] = ((block[0] & 0x03) << 3) +
-               ((block[1] & 0xe0) >> 5) + '@';
-       manufacturer[2] = (block[1] & 0x1f) + '@';
-       manufacturer[3] = 0;
-       model = block[2] + (block[3] << 8);
-
-       for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
-               if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
-                       brokendb[i].model == model) {
-                       fix = brokendb[i].fix;
-                       break;
-               }
-       }
-
-       switch (fix) {
-       case FBMON_FIX_HEADER:
-               for (i = 0; i < 8; i++) {
-                       if (edid[i] != edid_v1_header[i]) {
-                               ret = fix;
-                               break;
-                       }
-               }
-               break;
-       case FBMON_FIX_INPUT:
-               b = edid + EDID_STRUCT_DISPLAY;
-               /* Only if display is GTF capable will
-                  the input type be reset to analog */
-               if (b[4] & 0x01 && b[0] & 0x80)
-                       ret = fix;
-               break;
-       case FBMON_FIX_TIMINGS:
-               b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-               ret = fix;
-
-               for (i = 0; i < 4; i++) {
-                       if (edid_is_limits_block(b)) {
-                               ret = 0;
-                               break;
-                       }
-
-                       b += DETAILED_TIMING_DESCRIPTION_SIZE;
-               }
-
-               break;
-       }
-
-       if (ret)
-               printk("fbmon: The EDID Block of "
-                      "Manufacturer: %s Model: 0x%x is known to "
-                      "be broken,\n",  manufacturer, model);
-
-       return ret;
-}
-
-static void fix_edid(unsigned char *edid, int fix)
-{
-       int i;
-       unsigned char *b, csum = 0;
-
-       switch (fix) {
-       case FBMON_FIX_HEADER:
-               printk("fbmon: trying a header reconstruct\n");
-               memcpy(edid, edid_v1_header, 8);
-               break;
-       case FBMON_FIX_INPUT:
-               printk("fbmon: trying to fix input type\n");
-               b = edid + EDID_STRUCT_DISPLAY;
-               b[0] &= ~0x80;
-               edid[127] += 0x80;
-               break;
-       case FBMON_FIX_TIMINGS:
-               printk("fbmon: trying to fix monitor timings\n");
-               b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-               for (i = 0; i < 4; i++) {
-                       if (!(edid_is_serial_block(b) ||
-                             edid_is_ascii_block(b) ||
-                             edid_is_monitor_block(b) ||
-                             edid_is_timing_block(b))) {
-                               b[0] = 0x00;
-                               b[1] = 0x00;
-                               b[2] = 0x00;
-                               b[3] = 0xfd;
-                               b[4] = 0x00;
-                               b[5] = 60;   /* vfmin */
-                               b[6] = 60;   /* vfmax */
-                               b[7] = 30;   /* hfmin */
-                               b[8] = 75;   /* hfmax */
-                               b[9] = 17;   /* pixclock - 170 MHz*/
-                               b[10] = 0;   /* GTF */
-                               break;
-                       }
-
-                       b += DETAILED_TIMING_DESCRIPTION_SIZE;
-               }
-
-               for (i = 0; i < EDID_LENGTH - 1; i++)
-                       csum += edid[i];
-
-               edid[127] = 256 - csum;
-               break;
-       }
-}
-
-static int edid_checksum(unsigned char *edid)
-{
-       unsigned char csum = 0, all_null = 0;
-       int i, err = 0, fix = check_edid(edid);
-
-       if (fix)
-               fix_edid(edid, fix);
-
-       for (i = 0; i < EDID_LENGTH; i++) {
-               csum += edid[i];
-               all_null |= edid[i];
-       }
-
-       if (csum == 0x00 && all_null) {
-               /* checksum passed, everything's good */
-               err = 1;
-       }
-
-       return err;
-}
-
-static int edid_check_header(unsigned char *edid)
-{
-       int i, err = 1, fix = check_edid(edid);
-
-       if (fix)
-               fix_edid(edid, fix);
-
-       for (i = 0; i < 8; i++) {
-               if (edid[i] != edid_v1_header[i])
-                       err = 0;
-       }
-
-       return err;
-}
-
-static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
-{
-       specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
-       specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
-               ((block[1] & 0xe0) >> 5) + '@';
-       specs->manufacturer[2] = (block[1] & 0x1f) + '@';
-       specs->manufacturer[3] = 0;
-       specs->model = block[2] + (block[3] << 8);
-       specs->serial = block[4] + (block[5] << 8) +
-              (block[6] << 16) + (block[7] << 24);
-       specs->year = block[9] + 1990;
-       specs->week = block[8];
-       DPRINTK("   Manufacturer: %s\n", specs->manufacturer);
-       DPRINTK("   Model: %x\n", specs->model);
-       DPRINTK("   Serial#: %u\n", specs->serial);
-       DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);
-}
-
-static void get_dpms_capabilities(unsigned char flags,
-                                 struct fb_monspecs *specs)
-{
-       specs->dpms = 0;
-       if (flags & DPMS_ACTIVE_OFF)
-               specs->dpms |= FB_DPMS_ACTIVE_OFF;
-       if (flags & DPMS_SUSPEND)
-               specs->dpms |= FB_DPMS_SUSPEND;
-       if (flags & DPMS_STANDBY)
-               specs->dpms |= FB_DPMS_STANDBY;
-       DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
-              (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
-              (flags & DPMS_SUSPEND)    ? "yes" : "no",
-              (flags & DPMS_STANDBY)    ? "yes" : "no");
-}
-
-static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
-{
-       int tmp;
-
-       DPRINTK("      Chroma\n");
-       /* Chromaticity data */
-       tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.redx = tmp/1024;
-       DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);
-
-       tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.redy = tmp/1024;
-       DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);
-
-       tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.greenx = tmp/1024;
-       DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);
-
-       tmp = (block[5] & 3) | (block[0xa] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.greeny = tmp/1024;
-       DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);
-
-       tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.bluex = tmp/1024;
-       DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);
-
-       tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.bluey = tmp/1024;
-       DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
-
-       tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.whitex = tmp/1024;
-       DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);
-
-       tmp = (block[6] & 3) | (block[0xe] << 2);
-       tmp *= 1000;
-       tmp += 512;
-       specs->chroma.whitey = tmp/1024;
-       DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
-}
-
-static void calc_mode_timings(int xres, int yres, int refresh,
-                             struct fb_videomode *mode)
-{
-       struct fb_var_screeninfo *var;
-
-       var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
-
-       if (var) {
-               var->xres = xres;
-               var->yres = yres;
-               fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
-                           refresh, var, NULL);
-               mode->xres = xres;
-               mode->yres = yres;
-               mode->pixclock = var->pixclock;
-               mode->refresh = refresh;
-               mode->left_margin = var->left_margin;
-               mode->right_margin = var->right_margin;
-               mode->upper_margin = var->upper_margin;
-               mode->lower_margin = var->lower_margin;
-               mode->hsync_len = var->hsync_len;
-               mode->vsync_len = var->vsync_len;
-               mode->vmode = 0;
-               mode->sync = 0;
-               kfree(var);
-       }
-}
-
-static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
-{
-       int num = 0;
-       unsigned char c;
-
-       c = block[0];
-       if (c&0x80) {
-               calc_mode_timings(720, 400, 70, &mode[num]);
-               mode[num++].flag = FB_MODE_IS_CALCULATED;
-               DPRINTK("      720x400@70Hz\n");
-       }
-       if (c&0x40) {
-               calc_mode_timings(720, 400, 88, &mode[num]);
-               mode[num++].flag = FB_MODE_IS_CALCULATED;
-               DPRINTK("      720x400@88Hz\n");
-       }
-       if (c&0x20) {
-               mode[num++] = vesa_modes[3];
-               DPRINTK("      640x480@60Hz\n");
-       }
-       if (c&0x10) {
-               calc_mode_timings(640, 480, 67, &mode[num]);
-               mode[num++].flag = FB_MODE_IS_CALCULATED;
-               DPRINTK("      640x480@67Hz\n");
-       }
-       if (c&0x08) {
-               mode[num++] = vesa_modes[4];
-               DPRINTK("      640x480@72Hz\n");
-       }
-       if (c&0x04) {
-               mode[num++] = vesa_modes[5];
-               DPRINTK("      640x480@75Hz\n");
-       }
-       if (c&0x02) {
-               mode[num++] = vesa_modes[7];
-               DPRINTK("      800x600@56Hz\n");
-       }
-       if (c&0x01) {
-               mode[num++] = vesa_modes[8];
-               DPRINTK("      800x600@60Hz\n");
-       }
-
-       c = block[1];
-       if (c&0x80) {
-               mode[num++] = vesa_modes[9];
-               DPRINTK("      800x600@72Hz\n");
-       }
-       if (c&0x40) {
-               mode[num++] = vesa_modes[10];
-               DPRINTK("      800x600@75Hz\n");
-       }
-       if (c&0x20) {
-               calc_mode_timings(832, 624, 75, &mode[num]);
-               mode[num++].flag = FB_MODE_IS_CALCULATED;
-               DPRINTK("      832x624@75Hz\n");
-       }
-       if (c&0x10) {
-               mode[num++] = vesa_modes[12];
-               DPRINTK("      1024x768@87Hz Interlaced\n");
-       }
-       if (c&0x08) {
-               mode[num++] = vesa_modes[13];
-               DPRINTK("      1024x768@60Hz\n");
-       }
-       if (c&0x04) {
-               mode[num++] = vesa_modes[14];
-               DPRINTK("      1024x768@70Hz\n");
-       }
-       if (c&0x02) {
-               mode[num++] = vesa_modes[15];
-               DPRINTK("      1024x768@75Hz\n");
-       }
-       if (c&0x01) {
-               mode[num++] = vesa_modes[21];
-               DPRINTK("      1280x1024@75Hz\n");
-       }
-       c = block[2];
-       if (c&0x80) {
-               mode[num++] = vesa_modes[17];
-               DPRINTK("      1152x870@75Hz\n");
-       }
-       DPRINTK("      Manufacturer's mask: %x\n",c&0x7F);
-       return num;
-}
-
-static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
-               int ver, int rev)
-{
-       int xres, yres = 0, refresh, ratio, i;
-
-       xres = (block[0] + 31) * 8;
-       if (xres <= 256)
-               return 0;
-
-       ratio = (block[1] & 0xc0) >> 6;
-       switch (ratio) {
-       case 0:
-               /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
-               if (ver < 1 || (ver == 1 && rev < 3))
-                       yres = xres;
-               else
-                       yres = (xres * 10)/16;
-               break;
-       case 1:
-               yres = (xres * 3)/4;
-               break;
-       case 2:
-               yres = (xres * 4)/5;
-               break;
-       case 3:
-               yres = (xres * 9)/16;
-               break;
-       }
-       refresh = (block[1] & 0x3f) + 60;
-
-       DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
-       for (i = 0; i < VESA_MODEDB_SIZE; i++) {
-               if (vesa_modes[i].xres == xres &&
-                   vesa_modes[i].yres == yres &&
-                   vesa_modes[i].refresh == refresh) {
-                       *mode = vesa_modes[i];
-                       mode->flag |= FB_MODE_IS_STANDARD;
-                       return 1;
-               }
-       }
-       calc_mode_timings(xres, yres, refresh, mode);
-       return 1;
-}
-
-static int get_dst_timing(unsigned char *block,
-                         struct fb_videomode *mode, int ver, int rev)
-{
-       int j, num = 0;
-
-       for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
-               num += get_std_timing(block, &mode[num], ver, rev);
-
-       return num;
-}
-
-static void get_detailed_timing(unsigned char *block,
-                               struct fb_videomode *mode)
-{
-       mode->xres = H_ACTIVE;
-       mode->yres = V_ACTIVE;
-       mode->pixclock = PIXEL_CLOCK;
-       mode->pixclock /= 1000;
-       mode->pixclock = KHZ2PICOS(mode->pixclock);
-       mode->right_margin = H_SYNC_OFFSET;
-       mode->left_margin = (H_ACTIVE + H_BLANKING) -
-               (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
-       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
-               V_SYNC_WIDTH;
-       mode->lower_margin = V_SYNC_OFFSET;
-       mode->hsync_len = H_SYNC_WIDTH;
-       mode->vsync_len = V_SYNC_WIDTH;
-       if (HSYNC_POSITIVE)
-               mode->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if (VSYNC_POSITIVE)
-               mode->sync |= FB_SYNC_VERT_HIGH_ACT;
-       mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
-                                    (V_ACTIVE + V_BLANKING));
-       if (INTERLACED) {
-               mode->yres *= 2;
-               mode->upper_margin *= 2;
-               mode->lower_margin *= 2;
-               mode->vsync_len *= 2;
-               mode->vmode |= FB_VMODE_INTERLACED;
-       }
-       mode->flag = FB_MODE_IS_DETAILED;
-
-       DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);
-       DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
-              H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
-       DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
-              V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
-       DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
-              (VSYNC_POSITIVE) ? "+" : "-");
-}
-
-/**
- * fb_create_modedb - create video mode database
- * @edid: EDID data
- * @dbsize: database size
- *
- * RETURNS: struct fb_videomode, @dbsize contains length of database
- *
- * DESCRIPTION:
- * This function builds a mode database using the contents of the EDID
- * data
- */
-static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
-{
-       struct fb_videomode *mode, *m;
-       unsigned char *block;
-       int num = 0, i, first = 1;
-       int ver, rev;
-
-       ver = edid[EDID_STRUCT_VERSION];
-       rev = edid[EDID_STRUCT_REVISION];
-
-       mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
-       if (mode == NULL)
-               return NULL;
-
-       if (edid == NULL || !edid_checksum(edid) ||
-           !edid_check_header(edid)) {
-               kfree(mode);
-               return NULL;
-       }
-
-       *dbsize = 0;
-
-       DPRINTK("   Detailed Timings\n");
-       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-       for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
-               if (!(block[0] == 0x00 && block[1] == 0x00)) {
-                       get_detailed_timing(block, &mode[num]);
-                       if (first) {
-                               mode[num].flag |= FB_MODE_IS_FIRST;
-                               first = 0;
-                       }
-                       num++;
-               }
-       }
-
-       DPRINTK("   Supported VESA Modes\n");
-       block = edid + ESTABLISHED_TIMING_1;
-       num += get_est_timing(block, &mode[num]);
-
-       DPRINTK("   Standard Timings\n");
-       block = edid + STD_TIMING_DESCRIPTIONS_START;
-       for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
-               num += get_std_timing(block, &mode[num], ver, rev);
-
-       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-       for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
-               if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
-                       num += get_dst_timing(block + 5, &mode[num], ver, rev);
-       }
-
-       /* Yikes, EDID data is totally useless */
-       if (!num) {
-               kfree(mode);
-               return NULL;
-       }
-
-       *dbsize = num;
-       m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
-       if (!m)
-               return mode;
-       memmove(m, mode, num * sizeof(struct fb_videomode));
-       kfree(mode);
-       return m;
-}
-
-/**
- * fb_destroy_modedb - destroys mode database
- * @modedb: mode database to destroy
- *
- * DESCRIPTION:
- * Destroy mode database created by fb_create_modedb
- */
-void fb_destroy_modedb(struct fb_videomode *modedb)
-{
-       kfree(modedb);
-}
-
-static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
-{
-       int i, retval = 1;
-       unsigned char *block;
-
-       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-
-       DPRINTK("      Monitor Operating Limits: ");
-
-       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
-               if (edid_is_limits_block(block)) {
-                       specs->hfmin = H_MIN_RATE * 1000;
-                       specs->hfmax = H_MAX_RATE * 1000;
-                       specs->vfmin = V_MIN_RATE;
-                       specs->vfmax = V_MAX_RATE;
-                       specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
-                       specs->gtf = (GTF_SUPPORT) ? 1 : 0;
-                       retval = 0;
-                       DPRINTK("From EDID\n");
-                       break;
-               }
-       }
-
-       /* estimate monitor limits based on modes supported */
-       if (retval) {
-               struct fb_videomode *modes, *mode;
-               int num_modes, hz, hscan, pixclock;
-               int vtotal, htotal;
-
-               modes = fb_create_modedb(edid, &num_modes);
-               if (!modes) {
-                       DPRINTK("None Available\n");
-                       return 1;
-               }
-
-               retval = 0;
-               for (i = 0; i < num_modes; i++) {
-                       mode = &modes[i];
-                       pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
-                       htotal = mode->xres + mode->right_margin + mode->hsync_len
-                               + mode->left_margin;
-                       vtotal = mode->yres + mode->lower_margin + mode->vsync_len
-                               + mode->upper_margin;
-
-                       if (mode->vmode & FB_VMODE_INTERLACED)
-                               vtotal /= 2;
-
-                       if (mode->vmode & FB_VMODE_DOUBLE)
-                               vtotal *= 2;
-
-                       hscan = (pixclock + htotal / 2) / htotal;
-                       hscan = (hscan + 500) / 1000 * 1000;
-                       hz = (hscan + vtotal / 2) / vtotal;
-
-                       if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
-                               specs->dclkmax = pixclock;
-
-                       if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
-                               specs->dclkmin = pixclock;
-
-                       if (specs->hfmax == 0 || specs->hfmax < hscan)
-                               specs->hfmax = hscan;
-
-                       if (specs->hfmin == 0 || specs->hfmin > hscan)
-                               specs->hfmin = hscan;
-
-                       if (specs->vfmax == 0 || specs->vfmax < hz)
-                               specs->vfmax = hz;
-
-                       if (specs->vfmin == 0 || specs->vfmin > hz)
-                               specs->vfmin = hz;
-               }
-               DPRINTK("Extrapolated\n");
-               fb_destroy_modedb(modes);
-       }
-       DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
-               specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
-               specs->vfmax, specs->dclkmax/1000000);
-       return retval;
-}
-
-static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-       unsigned char c, *block;
-
-       block = edid + EDID_STRUCT_DISPLAY;
-
-       fb_get_monitor_limits(edid, specs);
-
-       c = block[0] & 0x80;
-       specs->input = 0;
-       if (c) {
-               specs->input |= FB_DISP_DDI;
-               DPRINTK("      Digital Display Input");
-       } else {
-               DPRINTK("      Analog Display Input: Input Voltage - ");
-               switch ((block[0] & 0x60) >> 5) {
-               case 0:
-                       DPRINTK("0.700V/0.300V");
-                       specs->input |= FB_DISP_ANA_700_300;
-                       break;
-               case 1:
-                       DPRINTK("0.714V/0.286V");
-                       specs->input |= FB_DISP_ANA_714_286;
-                       break;
-               case 2:
-                       DPRINTK("1.000V/0.400V");
-                       specs->input |= FB_DISP_ANA_1000_400;
-                       break;
-               case 3:
-                       DPRINTK("0.700V/0.000V");
-                       specs->input |= FB_DISP_ANA_700_000;
-                       break;
-               }
-       }
-       DPRINTK("\n      Sync: ");
-       c = block[0] & 0x10;
-       if (c)
-               DPRINTK("      Configurable signal level\n");
-       c = block[0] & 0x0f;
-       specs->signal = 0;
-       if (c & 0x10) {
-               DPRINTK("Blank to Blank ");
-               specs->signal |= FB_SIGNAL_BLANK_BLANK;
-       }
-       if (c & 0x08) {
-               DPRINTK("Separate ");
-               specs->signal |= FB_SIGNAL_SEPARATE;
-       }
-       if (c & 0x04) {
-               DPRINTK("Composite ");
-               specs->signal |= FB_SIGNAL_COMPOSITE;
-       }
-       if (c & 0x02) {
-               DPRINTK("Sync on Green ");
-               specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
-       }
-       if (c & 0x01) {
-               DPRINTK("Serration on ");
-               specs->signal |= FB_SIGNAL_SERRATION_ON;
-       }
-       DPRINTK("\n");
-       specs->max_x = block[1];
-       specs->max_y = block[2];
-       DPRINTK("      Max H-size in cm: ");
-       if (specs->max_x)
-               DPRINTK("%d\n", specs->max_x);
-       else
-               DPRINTK("variable\n");
-       DPRINTK("      Max V-size in cm: ");
-       if (specs->max_y)
-               DPRINTK("%d\n", specs->max_y);
-       else
-               DPRINTK("variable\n");
-
-       c = block[3];
-       specs->gamma = c+100;
-       DPRINTK("      Gamma: ");
-       DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
-
-       get_dpms_capabilities(block[4], specs);
-
-       switch ((block[4] & 0x18) >> 3) {
-       case 0:
-               DPRINTK("      Monochrome/Grayscale\n");
-               specs->input |= FB_DISP_MONO;
-               break;
-       case 1:
-               DPRINTK("      RGB Color Display\n");
-               specs->input |= FB_DISP_RGB;
-               break;
-       case 2:
-               DPRINTK("      Non-RGB Multicolor Display\n");
-               specs->input |= FB_DISP_MULTI;
-               break;
-       default:
-               DPRINTK("      Unknown\n");
-               specs->input |= FB_DISP_UNKNOWN;
-               break;
-       }
-
-       get_chroma(block, specs);
-
-       specs->misc = 0;
-       c = block[4] & 0x7;
-       if (c & 0x04) {
-               DPRINTK("      Default color format is primary\n");
-               specs->misc |= FB_MISC_PRIM_COLOR;
-       }
-       if (c & 0x02) {
-               DPRINTK("      First DETAILED Timing is preferred\n");
-               specs->misc |= FB_MISC_1ST_DETAIL;
-       }
-       if (c & 0x01) {
-               printk("      Display is GTF capable\n");
-               specs->gtf = 1;
-       }
-}
-
-int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
-{
-       int i;
-       unsigned char *block;
-
-       if (edid == NULL || var == NULL)
-               return 1;
-
-       if (!(edid_checksum(edid)))
-               return 1;
-
-       if (!(edid_check_header(edid)))
-               return 1;
-
-       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-
-       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
-               if (edid_is_timing_block(block)) {
-                       var->xres = var->xres_virtual = H_ACTIVE;
-                       var->yres = var->yres_virtual = V_ACTIVE;
-                       var->height = var->width = 0;
-                       var->right_margin = H_SYNC_OFFSET;
-                       var->left_margin = (H_ACTIVE + H_BLANKING) -
-                               (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
-                       var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
-                               V_SYNC_WIDTH;
-                       var->lower_margin = V_SYNC_OFFSET;
-                       var->hsync_len = H_SYNC_WIDTH;
-                       var->vsync_len = V_SYNC_WIDTH;
-                       var->pixclock = PIXEL_CLOCK;
-                       var->pixclock /= 1000;
-                       var->pixclock = KHZ2PICOS(var->pixclock);
-
-                       if (HSYNC_POSITIVE)
-                               var->sync |= FB_SYNC_HOR_HIGH_ACT;
-                       if (VSYNC_POSITIVE)
-                               var->sync |= FB_SYNC_VERT_HIGH_ACT;
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-       unsigned char *block;
-       int i, found = 0;
-
-       if (edid == NULL)
-               return;
-
-       if (!(edid_checksum(edid)))
-               return;
-
-       if (!(edid_check_header(edid)))
-               return;
-
-       memset(specs, 0, sizeof(struct fb_monspecs));
-
-       specs->version = edid[EDID_STRUCT_VERSION];
-       specs->revision = edid[EDID_STRUCT_REVISION];
-
-       DPRINTK("========================================\n");
-       DPRINTK("Display Information (EDID)\n");
-       DPRINTK("========================================\n");
-       DPRINTK("   EDID Version %d.%d\n", (int) specs->version,
-              (int) specs->revision);
-
-       parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
-
-       block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
-       for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
-               if (edid_is_serial_block(block)) {
-                       copy_string(block, specs->serial_no);
-                       DPRINTK("   Serial Number: %s\n", specs->serial_no);
-               } else if (edid_is_ascii_block(block)) {
-                       copy_string(block, specs->ascii);
-                       DPRINTK("   ASCII Block: %s\n", specs->ascii);
-               } else if (edid_is_monitor_block(block)) {
-                       copy_string(block, specs->monitor);
-                       DPRINTK("   Monitor Name: %s\n", specs->monitor);
-               }
-       }
-
-       DPRINTK("   Display Characteristics:\n");
-       get_monspecs(edid, specs);
-
-       specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
-
-       /*
-        * Workaround for buggy EDIDs that sets that the first
-        * detailed timing is preferred but has not detailed
-        * timing specified
-        */
-       for (i = 0; i < specs->modedb_len; i++) {
-               if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (!found)
-               specs->misc &= ~FB_MISC_1ST_DETAIL;
-
-       DPRINTK("========================================\n");
-}
-
-/**
- * fb_edid_add_monspecs() - add monitor video modes from E-EDID data
- * @edid:      128 byte array with an E-EDID block
- * @spacs:     monitor specs to be extended
- */
-void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-       unsigned char *block;
-       struct fb_videomode *m;
-       int num = 0, i;
-       u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE];
-       u8 pos = 4, svd_n = 0;
-
-       if (!edid)
-               return;
-
-       if (!edid_checksum(edid))
-               return;
-
-       if (edid[0] != 0x2 ||
-           edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
-               return;
-
-       DPRINTK("  Short Video Descriptors\n");
-
-       while (pos < edid[2]) {
-               u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
-               pr_debug("Data block %u of %u bytes\n", type, len);
-               if (type == 2)
-                       for (i = pos; i < pos + len; i++) {
-                               u8 idx = edid[pos + i] & 0x7f;
-                               svd[svd_n++] = idx;
-                               pr_debug("N%sative mode #%d\n",
-                                        edid[pos + i] & 0x80 ? "" : "on-n", idx);
-                       }
-               pos += len + 1;
-       }
-
-       block = edid + edid[2];
-
-       DPRINTK("  Extended Detailed Timings\n");
-
-       for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE;
-            i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
-               if (PIXEL_CLOCK)
-                       edt[num++] = block - edid;
-
-       /* Yikes, EDID data is totally useless */
-       if (!(num + svd_n))
-               return;
-
-       m = kzalloc((specs->modedb_len + num + svd_n) *
-                      sizeof(struct fb_videomode), GFP_KERNEL);
-
-       if (!m)
-               return;
-
-       memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode));
-
-       for (i = specs->modedb_len; i < specs->modedb_len + num; i++) {
-               get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]);
-               if (i == specs->modedb_len)
-                       m[i].flag |= FB_MODE_IS_FIRST;
-               pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh);
-       }
-
-       for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) {
-               int idx = svd[i - specs->modedb_len - num];
-               if (!idx || idx > 63) {
-                       pr_warning("Reserved SVD code %d\n", idx);
-               } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) {
-                       pr_warning("Unimplemented SVD code %d\n", idx);
-               } else {
-                       memcpy(&m[i], cea_modes + idx, sizeof(m[i]));
-                       pr_debug("Adding SVD #%d: %ux%u@%u\n", idx,
-                                m[i].xres, m[i].yres, m[i].refresh);
-               }
-       }
-
-       kfree(specs->modedb);
-       specs->modedb = m;
-       specs->modedb_len = specs->modedb_len + num + svd_n;
-}
-
-/*
- * VESA Generalized Timing Formula (GTF)
- */
-
-#define FLYBACK                     550
-#define V_FRONTPORCH                1
-#define H_OFFSET                    40
-#define H_SCALEFACTOR               20
-#define H_BLANKSCALE                128
-#define H_GRADIENT                  600
-#define C_VAL                       30
-#define M_VAL                       300
-
-struct __fb_timings {
-       u32 dclk;
-       u32 hfreq;
-       u32 vfreq;
-       u32 hactive;
-       u32 vactive;
-       u32 hblank;
-       u32 vblank;
-       u32 htotal;
-       u32 vtotal;
-};
-
-/**
- * fb_get_vblank - get vertical blank time
- * @hfreq: horizontal freq
- *
- * DESCRIPTION:
- * vblank = right_margin + vsync_len + left_margin
- *
- *    given: right_margin = 1 (V_FRONTPORCH)
- *           vsync_len    = 3
- *           flyback      = 550
- *
- *                          flyback * hfreq
- *           left_margin  = --------------- - vsync_len
- *                           1000000
- */
-static u32 fb_get_vblank(u32 hfreq)
-{
-       u32 vblank;
-
-       vblank = (hfreq * FLYBACK)/1000;
-       vblank = (vblank + 500)/1000;
-       return (vblank + V_FRONTPORCH);
-}
-
-/**
- * fb_get_hblank_by_freq - get horizontal blank time given hfreq
- * @hfreq: horizontal freq
- * @xres: horizontal resolution in pixels
- *
- * DESCRIPTION:
- *
- *           xres * duty_cycle
- * hblank = ------------------
- *           100 - duty_cycle
- *
- * duty cycle = percent of htotal assigned to inactive display
- * duty cycle = C - (M/Hfreq)
- *
- * where: C = ((offset - scale factor) * blank_scale)
- *            -------------------------------------- + scale factor
- *                        256
- *        M = blank_scale * gradient
- *
- */
-static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
-{
-       u32 c_val, m_val, duty_cycle, hblank;
-
-       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
-                H_SCALEFACTOR) * 1000;
-       m_val = (H_BLANKSCALE * H_GRADIENT)/256;
-       m_val = (m_val * 1000000)/hfreq;
-       duty_cycle = c_val - m_val;
-       hblank = (xres * duty_cycle)/(100000 - duty_cycle);
-       return (hblank);
-}
-
-/**
- * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
- * @dclk: pixelclock in Hz
- * @xres: horizontal resolution in pixels
- *
- * DESCRIPTION:
- *
- *           xres * duty_cycle
- * hblank = ------------------
- *           100 - duty_cycle
- *
- * duty cycle = percent of htotal assigned to inactive display
- * duty cycle = C - (M * h_period)
- *
- * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
- *                   -----------------------------------------------
- *                                    2 * M
- *        M = 300;
- *        C = 30;
-
- */
-static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
-{
-       u32 duty_cycle, h_period, hblank;
-
-       dclk /= 1000;
-       h_period = 100 - C_VAL;
-       h_period *= h_period;
-       h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
-       h_period *= 10000;
-
-       h_period = int_sqrt(h_period);
-       h_period -= (100 - C_VAL) * 100;
-       h_period *= 1000;
-       h_period /= 2 * M_VAL;
-
-       duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
-       hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
-       hblank &= ~15;
-       return (hblank);
-}
-
-/**
- * fb_get_hfreq - estimate hsync
- * @vfreq: vertical refresh rate
- * @yres: vertical resolution
- *
- * DESCRIPTION:
- *
- *          (yres + front_port) * vfreq * 1000000
- * hfreq = -------------------------------------
- *          (1000000 - (vfreq * FLYBACK)
- *
- */
-
-static u32 fb_get_hfreq(u32 vfreq, u32 yres)
-{
-       u32 divisor, hfreq;
-
-       divisor = (1000000 - (vfreq * FLYBACK))/1000;
-       hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
-       return (hfreq/divisor);
-}
-
-static void fb_timings_vfreq(struct __fb_timings *timings)
-{
-       timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
-       timings->vblank = fb_get_vblank(timings->hfreq);
-       timings->vtotal = timings->vactive + timings->vblank;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
-                                                timings->hactive);
-       timings->htotal = timings->hactive + timings->hblank;
-       timings->dclk = timings->htotal * timings->hfreq;
-}
-
-static void fb_timings_hfreq(struct __fb_timings *timings)
-{
-       timings->vblank = fb_get_vblank(timings->hfreq);
-       timings->vtotal = timings->vactive + timings->vblank;
-       timings->vfreq = timings->hfreq/timings->vtotal;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
-                                                timings->hactive);
-       timings->htotal = timings->hactive + timings->hblank;
-       timings->dclk = timings->htotal * timings->hfreq;
-}
-
-static void fb_timings_dclk(struct __fb_timings *timings)
-{
-       timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
-                                               timings->hactive);
-       timings->htotal = timings->hactive + timings->hblank;
-       timings->hfreq = timings->dclk/timings->htotal;
-       timings->vblank = fb_get_vblank(timings->hfreq);
-       timings->vtotal = timings->vactive + timings->vblank;
-       timings->vfreq = timings->hfreq/timings->vtotal;
-}
-
-/*
- * fb_get_mode - calculates video mode using VESA GTF
- * @flags: if: 0 - maximize vertical refresh rate
- *             1 - vrefresh-driven calculation;
- *             2 - hscan-driven calculation;
- *             3 - pixelclock-driven calculation;
- * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
- * @var: pointer to fb_var_screeninfo
- * @info: pointer to fb_info
- *
- * DESCRIPTION:
- * Calculates video mode based on monitor specs using VESA GTF.
- * The GTF is best for VESA GTF compliant monitors but is
- * specifically formulated to work for older monitors as well.
- *
- * If @flag==0, the function will attempt to maximize the
- * refresh rate.  Otherwise, it will calculate timings based on
- * the flag and accompanying value.
- *
- * If FB_IGNOREMON bit is set in @flags, monitor specs will be
- * ignored and @var will be filled with the calculated timings.
- *
- * All calculations are based on the VESA GTF Spreadsheet
- * available at VESA's public ftp (http://www.vesa.org).
- *
- * NOTES:
- * The timings generated by the GTF will be different from VESA
- * DMT.  It might be a good idea to keep a table of standard
- * VESA modes as well.  The GTF may also not work for some displays,
- * such as, and especially, analog TV.
- *
- * REQUIRES:
- * A valid info->monspecs, otherwise 'safe numbers' will be used.
- */
-int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
-{
-       struct __fb_timings *timings;
-       u32 interlace = 1, dscan = 1;
-       u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
-
-
-       timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
-
-       if (!timings)
-               return -ENOMEM;
-
-       /*
-        * If monspecs are invalid, use values that are enough
-        * for 640x480@60
-        */
-       if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
-           !info->monspecs.dclkmax ||
-           info->monspecs.hfmax < info->monspecs.hfmin ||
-           info->monspecs.vfmax < info->monspecs.vfmin ||
-           info->monspecs.dclkmax < info->monspecs.dclkmin) {
-               hfmin = 29000; hfmax = 30000;
-               vfmin = 60; vfmax = 60;
-               dclkmin = 0; dclkmax = 25000000;
-       } else {
-               hfmin = info->monspecs.hfmin;
-               hfmax = info->monspecs.hfmax;
-               vfmin = info->monspecs.vfmin;
-               vfmax = info->monspecs.vfmax;
-               dclkmin = info->monspecs.dclkmin;
-               dclkmax = info->monspecs.dclkmax;
-       }
-
-       timings->hactive = var->xres;
-       timings->vactive = var->yres;
-       if (var->vmode & FB_VMODE_INTERLACED) {
-               timings->vactive /= 2;
-               interlace = 2;
-       }
-       if (var->vmode & FB_VMODE_DOUBLE) {
-               timings->vactive *= 2;
-               dscan = 2;
-       }
-
-       switch (flags & ~FB_IGNOREMON) {
-       case FB_MAXTIMINGS: /* maximize refresh rate */
-               timings->hfreq = hfmax;
-               fb_timings_hfreq(timings);
-               if (timings->vfreq > vfmax) {
-                       timings->vfreq = vfmax;
-                       fb_timings_vfreq(timings);
-               }
-               if (timings->dclk > dclkmax) {
-                       timings->dclk = dclkmax;
-                       fb_timings_dclk(timings);
-               }
-               break;
-       case FB_VSYNCTIMINGS: /* vrefresh driven */
-               timings->vfreq = val;
-               fb_timings_vfreq(timings);
-               break;
-       case FB_HSYNCTIMINGS: /* hsync driven */
-               timings->hfreq = val;
-               fb_timings_hfreq(timings);
-               break;
-       case FB_DCLKTIMINGS: /* pixelclock driven */
-               timings->dclk = PICOS2KHZ(val) * 1000;
-               fb_timings_dclk(timings);
-               break;
-       default:
-               err = -EINVAL;
-
-       }
-
-       if (err || (!(flags & FB_IGNOREMON) &&
-           (timings->vfreq < vfmin || timings->vfreq > vfmax ||
-            timings->hfreq < hfmin || timings->hfreq > hfmax ||
-            timings->dclk < dclkmin || timings->dclk > dclkmax))) {
-               err = -EINVAL;
-       } else {
-               var->pixclock = KHZ2PICOS(timings->dclk/1000);
-               var->hsync_len = (timings->htotal * 8)/100;
-               var->right_margin = (timings->hblank/2) - var->hsync_len;
-               var->left_margin = timings->hblank - var->right_margin -
-                       var->hsync_len;
-               var->vsync_len = (3 * interlace)/dscan;
-               var->lower_margin = (1 * interlace)/dscan;
-               var->upper_margin = (timings->vblank * interlace)/dscan -
-                       (var->vsync_len + var->lower_margin);
-       }
-
-       kfree(timings);
-       return err;
-}
-
-#ifdef CONFIG_VIDEOMODE_HELPERS
-int fb_videomode_from_videomode(const struct videomode *vm,
-                               struct fb_videomode *fbmode)
-{
-       unsigned int htotal, vtotal;
-
-       fbmode->xres = vm->hactive;
-       fbmode->left_margin = vm->hback_porch;
-       fbmode->right_margin = vm->hfront_porch;
-       fbmode->hsync_len = vm->hsync_len;
-
-       fbmode->yres = vm->vactive;
-       fbmode->upper_margin = vm->vback_porch;
-       fbmode->lower_margin = vm->vfront_porch;
-       fbmode->vsync_len = vm->vsync_len;
-
-       /* prevent division by zero in KHZ2PICOS macro */
-       fbmode->pixclock = vm->pixelclock ?
-                       KHZ2PICOS(vm->pixelclock / 1000) : 0;
-
-       fbmode->sync = 0;
-       fbmode->vmode = 0;
-       if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
-               fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
-               fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
-       if (vm->flags & DISPLAY_FLAGS_INTERLACED)
-               fbmode->vmode |= FB_VMODE_INTERLACED;
-       if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
-               fbmode->vmode |= FB_VMODE_DOUBLE;
-       fbmode->flag = 0;
-
-       htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
-                vm->hsync_len;
-       vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
-                vm->vsync_len;
-       /* prevent division by zero */
-       if (htotal && vtotal) {
-               fbmode->refresh = vm->pixelclock / (htotal * vtotal);
-       /* a mode must have htotal and vtotal != 0 or it is invalid */
-       } else {
-               fbmode->refresh = 0;
-               return -EINVAL;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
-
-#ifdef CONFIG_OF
-static inline void dump_fb_videomode(const struct fb_videomode *m)
-{
-       pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
-                m->xres, m->yres, m->refresh, m->pixclock, m->left_margin,
-                m->right_margin, m->upper_margin, m->lower_margin,
-                m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
-}
-
-/**
- * of_get_fb_videomode - get a fb_videomode from devicetree
- * @np: device_node with the timing specification
- * @fb: will be set to the return value
- * @index: index into the list of display timings in devicetree
- *
- * DESCRIPTION:
- * This function is expensive and should only be used, if only one mode is to be
- * read from DT. To get multiple modes start with of_get_display_timings ond
- * work with that instead.
- */
-int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
-                       int index)
-{
-       struct videomode vm;
-       int ret;
-
-       ret = of_get_videomode(np, &vm, index);
-       if (ret)
-               return ret;
-
-       fb_videomode_from_videomode(&vm, fb);
-
-       pr_debug("%s: got %dx%d display mode from %s\n",
-               of_node_full_name(np), vm.hactive, vm.vactive, np->name);
-       dump_fb_videomode(fb);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(of_get_fb_videomode);
-#endif /* CONFIG_OF */
-#endif /* CONFIG_VIDEOMODE_HELPERS */
-
-#else
-int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
-{
-       return 1;
-}
-void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-       specs = NULL;
-}
-void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
-{
-}
-void fb_destroy_modedb(struct fb_videomode *modedb)
-{
-}
-int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
-               struct fb_info *info)
-{
-       return -EINVAL;
-}
-#endif /* CONFIG_FB_MODE_HELPERS */
-
-/*
- * fb_validate_mode - validates var against monitor capabilities
- * @var: pointer to fb_var_screeninfo
- * @info: pointer to fb_info
- *
- * DESCRIPTION:
- * Validates video mode against monitor capabilities specified in
- * info->monspecs.
- *
- * REQUIRES:
- * A valid info->monspecs.
- */
-int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
-{
-       u32 hfreq, vfreq, htotal, vtotal, pixclock;
-       u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
-
-       /*
-        * If monspecs are invalid, use values that are enough
-        * for 640x480@60
-        */
-       if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
-           !info->monspecs.dclkmax ||
-           info->monspecs.hfmax < info->monspecs.hfmin ||
-           info->monspecs.vfmax < info->monspecs.vfmin ||
-           info->monspecs.dclkmax < info->monspecs.dclkmin) {
-               hfmin = 29000; hfmax = 30000;
-               vfmin = 60; vfmax = 60;
-               dclkmin = 0; dclkmax = 25000000;
-       } else {
-               hfmin = info->monspecs.hfmin;
-               hfmax = info->monspecs.hfmax;
-               vfmin = info->monspecs.vfmin;
-               vfmax = info->monspecs.vfmax;
-               dclkmin = info->monspecs.dclkmin;
-               dclkmax = info->monspecs.dclkmax;
-       }
-
-       if (!var->pixclock)
-               return -EINVAL;
-       pixclock = PICOS2KHZ(var->pixclock) * 1000;
-
-       htotal = var->xres + var->right_margin + var->hsync_len +
-               var->left_margin;
-       vtotal = var->yres + var->lower_margin + var->vsync_len +
-               var->upper_margin;
-
-       if (var->vmode & FB_VMODE_INTERLACED)
-               vtotal /= 2;
-       if (var->vmode & FB_VMODE_DOUBLE)
-               vtotal *= 2;
-
-       hfreq = pixclock/htotal;
-       hfreq = (hfreq + 500) / 1000 * 1000;
-
-       vfreq = hfreq/vtotal;
-
-       return (vfreq < vfmin || vfreq > vfmax ||
-               hfreq < hfmin || hfreq > hfmax ||
-               pixclock < dclkmin || pixclock > dclkmax) ?
-               -EINVAL : 0;
-}
-
-#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
-
-/*
- * We need to ensure that the EDID block is only returned for
- * the primary graphics adapter.
- */
-
-const unsigned char *fb_firmware_edid(struct device *device)
-{
-       struct pci_dev *dev = NULL;
-       struct resource *res = NULL;
-       unsigned char *edid = NULL;
-
-       if (device)
-               dev = to_pci_dev(device);
-
-       if (dev)
-               res = &dev->resource[PCI_ROM_RESOURCE];
-
-       if (res && res->flags & IORESOURCE_ROM_SHADOW)
-               edid = edid_info.dummy;
-
-       return edid;
-}
-#else
-const unsigned char *fb_firmware_edid(struct device *device)
-{
-       return NULL;
-}
-#endif
-EXPORT_SYMBOL(fb_firmware_edid);
-
-EXPORT_SYMBOL(fb_parse_edid);
-EXPORT_SYMBOL(fb_edid_to_monspecs);
-EXPORT_SYMBOL(fb_edid_add_monspecs);
-EXPORT_SYMBOL(fb_get_mode);
-EXPORT_SYMBOL(fb_validate_mode);
-EXPORT_SYMBOL(fb_destroy_modedb);
diff --git a/drivers/video/fbdev/fbsysfs.c b/drivers/video/fbdev/fbsysfs.c
deleted file mode 100644 (file)
index 53444ac..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * fbsysfs.c - framebuffer device class and attributes
- *
- * Copyright (c) 2004 James Simmons <jsimmons@infradead.org>
- * 
- *     This program is free software you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- */
-
-/*
- * Note:  currently there's only stubs for framebuffer_alloc and
- * framebuffer_release here.  The reson for that is that until all drivers
- * are converted to use it a sysfsification will open OOPSable races.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include <linux/console.h>
-#include <linux/module.h>
-
-#define FB_SYSFS_FLAG_ATTR 1
-
-/**
- * framebuffer_alloc - creates a new frame buffer info structure
- *
- * @size: size of driver private data, can be zero
- * @dev: pointer to the device for this fb, this can be NULL
- *
- * Creates a new frame buffer info structure. Also reserves @size bytes
- * for driver private data (info->par). info->par (if any) will be
- * aligned to sizeof(long).
- *
- * Returns the new structure, or NULL if an error occurred.
- *
- */
-struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
-{
-#define BYTES_PER_LONG (BITS_PER_LONG/8)
-#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
-       int fb_info_size = sizeof(struct fb_info);
-       struct fb_info *info;
-       char *p;
-
-       if (size)
-               fb_info_size += PADDING;
-
-       p = kzalloc(fb_info_size + size, GFP_KERNEL);
-
-       if (!p)
-               return NULL;
-
-       info = (struct fb_info *) p;
-
-       if (size)
-               info->par = p + fb_info_size;
-
-       info->device = dev;
-
-#ifdef CONFIG_FB_BACKLIGHT
-       mutex_init(&info->bl_curve_mutex);
-#endif
-
-       return info;
-#undef PADDING
-#undef BYTES_PER_LONG
-}
-EXPORT_SYMBOL(framebuffer_alloc);
-
-/**
- * framebuffer_release - marks the structure available for freeing
- *
- * @info: frame buffer info structure
- *
- * Drop the reference count of the device embedded in the
- * framebuffer info structure.
- *
- */
-void framebuffer_release(struct fb_info *info)
-{
-       if (!info)
-               return;
-       kfree(info->apertures);
-       kfree(info);
-}
-EXPORT_SYMBOL(framebuffer_release);
-
-static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
-{
-       int err;
-
-       var->activate |= FB_ACTIVATE_FORCE;
-       console_lock();
-       fb_info->flags |= FBINFO_MISC_USEREVENT;
-       err = fb_set_var(fb_info, var);
-       fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       console_unlock();
-       if (err)
-               return err;
-       return 0;
-}
-
-static int mode_string(char *buf, unsigned int offset,
-                      const struct fb_videomode *mode)
-{
-       char m = 'U';
-       char v = 'p';
-
-       if (mode->flag & FB_MODE_IS_DETAILED)
-               m = 'D';
-       if (mode->flag & FB_MODE_IS_VESA)
-               m = 'V';
-       if (mode->flag & FB_MODE_IS_STANDARD)
-               m = 'S';
-
-       if (mode->vmode & FB_VMODE_INTERLACED)
-               v = 'i';
-       if (mode->vmode & FB_VMODE_DOUBLE)
-               v = 'd';
-
-       return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
-                       m, mode->xres, mode->yres, v, mode->refresh);
-}
-
-static ssize_t store_mode(struct device *device, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       char mstr[100];
-       struct fb_var_screeninfo var;
-       struct fb_modelist *modelist;
-       struct fb_videomode *mode;
-       struct list_head *pos;
-       size_t i;
-       int err;
-
-       memset(&var, 0, sizeof(var));
-
-       list_for_each(pos, &fb_info->modelist) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               mode = &modelist->mode;
-               i = mode_string(mstr, 0, mode);
-               if (strncmp(mstr, buf, max(count, i)) == 0) {
-
-                       var = fb_info->var;
-                       fb_videomode_to_var(&var, mode);
-                       if ((err = activate(fb_info, &var)))
-                               return err;
-                       fb_info->mode = mode;
-                       return count;
-               }
-       }
-       return -EINVAL;
-}
-
-static ssize_t show_mode(struct device *device, struct device_attribute *attr,
-                        char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-
-       if (!fb_info->mode)
-               return 0;
-
-       return mode_string(buf, 0, fb_info->mode);
-}
-
-static ssize_t store_modes(struct device *device,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       LIST_HEAD(old_list);
-       int i = count / sizeof(struct fb_videomode);
-
-       if (i * sizeof(struct fb_videomode) != count)
-               return -EINVAL;
-
-       console_lock();
-       if (!lock_fb_info(fb_info)) {
-               console_unlock();
-               return -ENODEV;
-       }
-
-       list_splice(&fb_info->modelist, &old_list);
-       fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
-                                &fb_info->modelist);
-       if (fb_new_modelist(fb_info)) {
-               fb_destroy_modelist(&fb_info->modelist);
-               list_splice(&old_list, &fb_info->modelist);
-       } else
-               fb_destroy_modelist(&old_list);
-
-       unlock_fb_info(fb_info);
-       console_unlock();
-
-       return 0;
-}
-
-static ssize_t show_modes(struct device *device, struct device_attribute *attr,
-                         char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       unsigned int i;
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       const struct fb_videomode *mode;
-
-       i = 0;
-       list_for_each(pos, &fb_info->modelist) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               mode = &modelist->mode;
-               i += mode_string(buf, i, mode);
-       }
-       return i;
-}
-
-static ssize_t store_bpp(struct device *device, struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       struct fb_var_screeninfo var;
-       char ** last = NULL;
-       int err;
-
-       var = fb_info->var;
-       var.bits_per_pixel = simple_strtoul(buf, last, 0);
-       if ((err = activate(fb_info, &var)))
-               return err;
-       return count;
-}
-
-static ssize_t show_bpp(struct device *device, struct device_attribute *attr,
-                       char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
-}
-
-static ssize_t store_rotate(struct device *device,
-                           struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       struct fb_var_screeninfo var;
-       char **last = NULL;
-       int err;
-
-       var = fb_info->var;
-       var.rotate = simple_strtoul(buf, last, 0);
-
-       if ((err = activate(fb_info, &var)))
-               return err;
-
-       return count;
-}
-
-
-static ssize_t show_rotate(struct device *device,
-                          struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
-}
-
-static ssize_t store_virtual(struct device *device,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       struct fb_var_screeninfo var;
-       char *last = NULL;
-       int err;
-
-       var = fb_info->var;
-       var.xres_virtual = simple_strtoul(buf, &last, 0);
-       last++;
-       if (last - buf >= count)
-               return -EINVAL;
-       var.yres_virtual = simple_strtoul(last, &last, 0);
-
-       if ((err = activate(fb_info, &var)))
-               return err;
-       return count;
-}
-
-static ssize_t show_virtual(struct device *device,
-                           struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xres_virtual,
-                       fb_info->var.yres_virtual);
-}
-
-static ssize_t show_stride(struct device *device,
-                          struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->fix.line_length);
-}
-
-static ssize_t store_blank(struct device *device,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       char *last = NULL;
-       int err;
-
-       console_lock();
-       fb_info->flags |= FBINFO_MISC_USEREVENT;
-       err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
-       fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       console_unlock();
-       if (err < 0)
-               return err;
-       return count;
-}
-
-static ssize_t show_blank(struct device *device,
-                         struct device_attribute *attr, char *buf)
-{
-//     struct fb_info *fb_info = dev_get_drvdata(device);
-       return 0;
-}
-
-static ssize_t store_console(struct device *device,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-//     struct fb_info *fb_info = dev_get_drvdata(device);
-       return 0;
-}
-
-static ssize_t show_console(struct device *device,
-                           struct device_attribute *attr, char *buf)
-{
-//     struct fb_info *fb_info = dev_get_drvdata(device);
-       return 0;
-}
-
-static ssize_t store_cursor(struct device *device,
-                           struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-//     struct fb_info *fb_info = dev_get_drvdata(device);
-       return 0;
-}
-
-static ssize_t show_cursor(struct device *device,
-                          struct device_attribute *attr, char *buf)
-{
-//     struct fb_info *fb_info = dev_get_drvdata(device);
-       return 0;
-}
-
-static ssize_t store_pan(struct device *device,
-                        struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       struct fb_var_screeninfo var;
-       char *last = NULL;
-       int err;
-
-       var = fb_info->var;
-       var.xoffset = simple_strtoul(buf, &last, 0);
-       last++;
-       if (last - buf >= count)
-               return -EINVAL;
-       var.yoffset = simple_strtoul(last, &last, 0);
-
-       console_lock();
-       err = fb_pan_display(fb_info, &var);
-       console_unlock();
-
-       if (err < 0)
-               return err;
-       return count;
-}
-
-static ssize_t show_pan(struct device *device,
-                       struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
-                       fb_info->var.yoffset);
-}
-
-static ssize_t show_name(struct device *device,
-                        struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-
-       return snprintf(buf, PAGE_SIZE, "%s\n", fb_info->fix.id);
-}
-
-static ssize_t store_fbstate(struct device *device,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       u32 state;
-       char *last = NULL;
-
-       state = simple_strtoul(buf, &last, 0);
-
-       console_lock();
-       if (!lock_fb_info(fb_info)) {
-               console_unlock();
-               return -ENODEV;
-       }
-
-       fb_set_suspend(fb_info, (int)state);
-
-       unlock_fb_info(fb_info);
-       console_unlock();
-
-       return count;
-}
-
-static ssize_t show_fbstate(struct device *device,
-                           struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
-}
-
-#ifdef CONFIG_FB_BACKLIGHT
-static ssize_t store_bl_curve(struct device *device,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       u8 tmp_curve[FB_BACKLIGHT_LEVELS];
-       unsigned int i;
-
-       /* Some drivers don't use framebuffer_alloc(), but those also
-        * don't have backlights.
-        */
-       if (!fb_info || !fb_info->bl_dev)
-               return -ENODEV;
-
-       if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
-               return -EINVAL;
-
-       for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
-               if (sscanf(&buf[i * 24],
-                       "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
-                       &tmp_curve[i * 8 + 0],
-                       &tmp_curve[i * 8 + 1],
-                       &tmp_curve[i * 8 + 2],
-                       &tmp_curve[i * 8 + 3],
-                       &tmp_curve[i * 8 + 4],
-                       &tmp_curve[i * 8 + 5],
-                       &tmp_curve[i * 8 + 6],
-                       &tmp_curve[i * 8 + 7]) != 8)
-                       return -EINVAL;
-
-       /* If there has been an error in the input data, we won't
-        * reach this loop.
-        */
-       mutex_lock(&fb_info->bl_curve_mutex);
-       for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
-               fb_info->bl_curve[i] = tmp_curve[i];
-       mutex_unlock(&fb_info->bl_curve_mutex);
-
-       return count;
-}
-
-static ssize_t show_bl_curve(struct device *device,
-                            struct device_attribute *attr, char *buf)
-{
-       struct fb_info *fb_info = dev_get_drvdata(device);
-       ssize_t len = 0;
-       unsigned int i;
-
-       /* Some drivers don't use framebuffer_alloc(), but those also
-        * don't have backlights.
-        */
-       if (!fb_info || !fb_info->bl_dev)
-               return -ENODEV;
-
-       mutex_lock(&fb_info->bl_curve_mutex);
-       for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
-               len += snprintf(&buf[len], PAGE_SIZE,
-                               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                               fb_info->bl_curve[i + 0],
-                               fb_info->bl_curve[i + 1],
-                               fb_info->bl_curve[i + 2],
-                               fb_info->bl_curve[i + 3],
-                               fb_info->bl_curve[i + 4],
-                               fb_info->bl_curve[i + 5],
-                               fb_info->bl_curve[i + 6],
-                               fb_info->bl_curve[i + 7]);
-       mutex_unlock(&fb_info->bl_curve_mutex);
-
-       return len;
-}
-#endif
-
-/* When cmap is added back in it should be a binary attribute
- * not a text one. Consideration should also be given to converting
- * fbdev to use configfs instead of sysfs */
-static struct device_attribute device_attrs[] = {
-       __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
-       __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
-       __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
-       __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
-       __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
-       __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
-       __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
-       __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
-       __ATTR(name, S_IRUGO, show_name, NULL),
-       __ATTR(stride, S_IRUGO, show_stride, NULL),
-       __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
-       __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
-#ifdef CONFIG_FB_BACKLIGHT
-       __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
-#endif
-};
-
-int fb_init_device(struct fb_info *fb_info)
-{
-       int i, error = 0;
-
-       dev_set_drvdata(fb_info->dev, fb_info);
-
-       fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
-
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               error = device_create_file(fb_info->dev, &device_attrs[i]);
-
-               if (error)
-                       break;
-       }
-
-       if (error) {
-               while (--i >= 0)
-                       device_remove_file(fb_info->dev, &device_attrs[i]);
-               fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
-       }
-
-       return 0;
-}
-
-void fb_cleanup_device(struct fb_info *fb_info)
-{
-       unsigned int i;
-
-       if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
-               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-                       device_remove_file(fb_info->dev, &device_attrs[i]);
-
-               fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
-       }
-}
-
-#ifdef CONFIG_FB_BACKLIGHT
-/* This function generates a linear backlight curve
- *
- *     0: off
- *   1-7: min
- * 8-127: linear from min to max
- */
-void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
-{
-       unsigned int i, flat, count, range = (max - min);
-
-       mutex_lock(&fb_info->bl_curve_mutex);
-
-       fb_info->bl_curve[0] = off;
-
-       for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
-               fb_info->bl_curve[flat] = min;
-
-       count = FB_BACKLIGHT_LEVELS * 15 / 16;
-       for (i = 0; i < count; ++i)
-               fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
-
-       mutex_unlock(&fb_info->bl_curve_mutex);
-}
-EXPORT_SYMBOL_GPL(fb_bl_default_curve);
-#endif
diff --git a/drivers/video/fbdev/modedb.c b/drivers/video/fbdev/modedb.c
deleted file mode 100644 (file)
index a9a907c..0000000
+++ /dev/null
@@ -1,1137 +0,0 @@
-/*
- *  linux/drivers/video/modedb.c -- Standard video mode database management
- *
- *     Copyright (C) 1999 Geert Uytterhoeven
- *
- *     2001 - Documented with DocBook
- *     - Brad Douglas <brad@neruo.com>
- *
- *  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.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include <linux/kernel.h>
-
-#undef DEBUG
-
-#define name_matches(v, s, l) \
-    ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
-#define res_matches(v, x, y) \
-    ((v).xres == (x) && (v).yres == (y))
-
-#ifdef DEBUG
-#define DPRINTK(fmt, args...)  printk("modedb %s: " fmt, __func__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-const char *fb_mode_option;
-EXPORT_SYMBOL_GPL(fb_mode_option);
-
-/*
- *  Standard video mode definitions (taken from XFree86)
- */
-
-static const struct fb_videomode modedb[] = {
-
-       /* 640x400 @ 70 Hz, 31.5 kHz hsync */
-       { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 640x480 @ 60 Hz, 31.5 kHz hsync */
-       { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,     0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 800x600 @ 56 Hz, 35.15 kHz hsync */
-       { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,     0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
-       { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0,
-               FB_VMODE_INTERLACED },
-
-       /* 640x400 @ 85 Hz, 37.86 kHz hsync */
-       { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
-               FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
-
-       /* 640x480 @ 72 Hz, 36.5 kHz hsync */
-       { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 640x480 @ 75 Hz, 37.50 kHz hsync */
-       { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,     0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 800x600 @ 60 Hz, 37.8 kHz hsync */
-       { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 640x480 @ 85 Hz, 43.27 kHz hsync */
-       { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
-       { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0,
-               FB_VMODE_INTERLACED },
-       /* 800x600 @ 72 Hz, 48.0 kHz hsync */
-       { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 60 Hz, 48.4 kHz hsync */
-       { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 640x480 @ 100 Hz, 53.01 kHz hsync */
-       { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,     0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 60 Hz, 53.5 kHz hsync */
-       { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 800x600 @ 85 Hz, 55.84 kHz hsync */
-       { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 70 Hz, 56.5 kHz hsync */
-       { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
-       { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
-               FB_VMODE_INTERLACED },
-
-       /* 800x600 @ 100 Hz, 64.02 kHz hsync */
-       { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 76 Hz, 62.5 kHz hsync */
-       { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 70 Hz, 62.4 kHz hsync */
-       { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
-       { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1400x1050 @ 60Hz, 63.9 kHz hsync */
-       { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
-       { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
-       { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 85 Hz, 70.24 kHz hsync */
-       { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 78 Hz, 70.8 kHz hsync */
-       { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
-       { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1600x1200 @ 60Hz, 75.00 kHz hsync */
-       { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 84 Hz, 76.0 kHz hsync */
-       { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
-       { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1024x768 @ 100Hz, 80.21 kHz hsync */
-       { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
-       { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
-       { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x864 @ 100 Hz, 89.62 kHz hsync */
-       { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
-       { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
-       { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */
-       { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
-       { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
-       { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1800x1440 @ 64Hz, 96.15 kHz hsync  */
-       { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1800x1440 @ 70Hz, 104.52 kHz hsync  */
-       { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 512x384 @ 78 Hz, 31.50 kHz hsync */
-       { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 512x384 @ 85 Hz, 34.38 kHz hsync */
-       { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
-       { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
-       { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 320x240 @ 72 Hz, 36.5 kHz hsync */
-       { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
-       { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 400x300 @ 60 Hz, 37.8 kHz hsync */
-       { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 400x300 @ 72 Hz, 48.0 kHz hsync */
-       { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,     0,
-               FB_VMODE_DOUBLE },
-
-       /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
-       { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 480x300 @ 60 Hz, 37.8 kHz hsync */
-       { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 480x300 @ 63 Hz, 39.6 kHz hsync */
-       { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 480x300 @ 72 Hz, 48.0 kHz hsync */
-       { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0,
-               FB_VMODE_DOUBLE },
-
-       /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */
-       { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
-       { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
-       { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
-       { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0,
-               FB_VMODE_NONINTERLACED },
-
-       /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
-       { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0,
-               FB_VMODE_INTERLACED },
-
-       /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
-       { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0,
-               FB_VMODE_INTERLACED },
-
-       /* 864x480 @ 60 Hz, 35.15 kHz hsync */
-       { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0,
-               0, FB_VMODE_NONINTERLACED },
-};
-
-#ifdef CONFIG_FB_MODE_HELPERS
-const struct fb_videomode cea_modes[64] = {
-       /* #1: 640x480p@59.94/60Hz */
-       [1] = {
-               NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #3: 720x480p@59.94/60Hz */
-       [3] = {
-               NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #5: 1920x1080i@59.94/60Hz */
-       [5] = {
-               NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_INTERLACED, 0,
-       },
-       /* #7: 720(1440)x480iH@59.94/60Hz */
-       [7] = {
-               NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
-               FB_VMODE_INTERLACED, 0,
-       },
-       /* #9: 720(1440)x240pH@59.94/60Hz */
-       [9] = {
-               NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #18: 720x576pH@50Hz */
-       [18] = {
-               NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #19: 1280x720p@50Hz */
-       [19] = {
-               NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #20: 1920x1080i@50Hz */
-       [20] = {
-               NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_INTERLACED, 0,
-       },
-       /* #32: 1920x1080p@23.98/24Hz */
-       [32] = {
-               NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
-               FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-       /* #35: (2880)x480p4x@59.94/60Hz */
-       [35] = {
-               NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0,
-               FB_VMODE_NONINTERLACED, 0,
-       },
-};
-
-const struct fb_videomode vesa_modes[] = {
-       /* 0 640x350-85 VESA */
-       { NULL, 85, 640, 350, 31746,  96, 32, 60, 32, 64, 3,
-         FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
-       /* 1 640x400-85 VESA */
-       { NULL, 85, 640, 400, 31746,  96, 32, 41, 01, 64, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 2 720x400-85 VESA */
-       { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 3 640x480-60 VESA */
-       { NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 4 640x480-72 VESA */
-       { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 5 640x480-75 VESA */
-       { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 6 640x480-85 VESA */
-       { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 7 800x600-56 VESA */
-       { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 8 800x600-60 VESA */
-       { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 9 800x600-72 VESA */
-       { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 10 800x600-75 VESA */
-       { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 11 800x600-85 VESA */
-       { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-        /* 12 1024x768i-43 VESA */
-       { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
-       /* 13 1024x768-60 VESA */
-       { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 14 1024x768-70 VESA */
-       { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
-         0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 15 1024x768-75 VESA */
-       { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 16 1024x768-85 VESA */
-       { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 17 1152x864-75 VESA */
-       { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 18 1280x960-60 VESA */
-       { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 19 1280x960-85 VESA */
-       { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 20 1280x1024-60 VESA */
-       { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 21 1280x1024-75 VESA */
-       { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 22 1280x1024-85 VESA */
-       { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 23 1600x1200-60 VESA */
-       { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 24 1600x1200-65 VESA */
-       { NULL, 65, 1600, 1200, 5698, 304,  64, 46, 1, 192, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 25 1600x1200-70 VESA */
-       { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 26 1600x1200-75 VESA */
-       { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 27 1600x1200-85 VESA */
-       { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
-         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-         FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 28 1792x1344-60 VESA */
-       { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 29 1792x1344-75 VESA */
-       { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 30 1856x1392-60 VESA */
-       { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 31 1856x1392-75 VESA */
-       { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 32 1920x1440-60 VESA */
-       { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-       /* 33 1920x1440-75 VESA */
-       { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
-         FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
-};
-EXPORT_SYMBOL(vesa_modes);
-#endif /* CONFIG_FB_MODE_HELPERS */
-
-/**
- *     fb_try_mode - test a video mode
- *     @var: frame buffer user defined part of display
- *     @info: frame buffer info structure
- *     @mode: frame buffer video mode structure
- *     @bpp: color depth in bits per pixel
- *
- *     Tries a video mode to test it's validity for device @info.
- *
- *     Returns 1 on success.
- *
- */
-
-static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
-                      const struct fb_videomode *mode, unsigned int bpp)
-{
-       int err = 0;
-
-       DPRINTK("Trying mode %s %dx%d-%d@%d\n",
-               mode->name ? mode->name : "noname",
-               mode->xres, mode->yres, bpp, mode->refresh);
-       var->xres = mode->xres;
-       var->yres = mode->yres;
-       var->xres_virtual = mode->xres;
-       var->yres_virtual = mode->yres;
-       var->xoffset = 0;
-       var->yoffset = 0;
-       var->bits_per_pixel = bpp;
-       var->activate |= FB_ACTIVATE_TEST;
-       var->pixclock = mode->pixclock;
-       var->left_margin = mode->left_margin;
-       var->right_margin = mode->right_margin;
-       var->upper_margin = mode->upper_margin;
-       var->lower_margin = mode->lower_margin;
-       var->hsync_len = mode->hsync_len;
-       var->vsync_len = mode->vsync_len;
-       var->sync = mode->sync;
-       var->vmode = mode->vmode;
-       if (info->fbops->fb_check_var)
-               err = info->fbops->fb_check_var(var, info);
-       var->activate &= ~FB_ACTIVATE_TEST;
-       return err;
-}
-
-/**
- *     fb_find_mode - finds a valid video mode
- *     @var: frame buffer user defined part of display
- *     @info: frame buffer info structure
- *     @mode_option: string video mode to find
- *     @db: video mode database
- *     @dbsize: size of @db
- *     @default_mode: default video mode to fall back to
- *     @default_bpp: default color depth in bits per pixel
- *
- *     Finds a suitable video mode, starting with the specified mode
- *     in @mode_option with fallback to @default_mode.  If
- *     @default_mode fails, all modes in the video mode database will
- *     be tried.
- *
- *     Valid mode specifiers for @mode_option:
- *
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
- *     <name>[-<bpp>][@<refresh>]
- *
- *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
- *     <name> a string.
- *
- *      If 'M' is present after yres (and before refresh/bpp if present),
- *      the function will compute the timings using VESA(tm) Coordinated
- *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
- *      reduced blanking (for flatpanels).  If 'i' is present, compute
- *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
- *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
- *      'i' and 'm' must be after 'M' and 'R'. Example:
- *
- *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
- *
- *     NOTE: The passed struct @var is _not_ cleared!  This allows you
- *     to supply values for e.g. the grayscale and accel_flags fields.
- *
- *     Returns zero for failure, 1 if using specified @mode_option,
- *     2 if using specified @mode_option with an ignored refresh rate,
- *     3 if default mode is used, 4 if fall back to any valid mode.
- *
- */
-
-int fb_find_mode(struct fb_var_screeninfo *var,
-                struct fb_info *info, const char *mode_option,
-                const struct fb_videomode *db, unsigned int dbsize,
-                const struct fb_videomode *default_mode,
-                unsigned int default_bpp)
-{
-       int i;
-
-       /* Set up defaults */
-       if (!db) {
-               db = modedb;
-               dbsize = ARRAY_SIZE(modedb);
-       }
-
-       if (!default_mode)
-               default_mode = &db[0];
-
-       if (!default_bpp)
-               default_bpp = 8;
-
-       /* Did the user specify a video mode? */
-       if (!mode_option)
-               mode_option = fb_mode_option;
-       if (mode_option) {
-               const char *name = mode_option;
-               unsigned int namelen = strlen(name);
-               int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-               unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
-               int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
-               int margins = 0;
-               u32 best, diff, tdiff;
-
-               for (i = namelen-1; i >= 0; i--) {
-                       switch (name[i]) {
-                       case '@':
-                               namelen = i;
-                               if (!refresh_specified && !bpp_specified &&
-                                   !yres_specified) {
-                                       refresh = simple_strtol(&name[i+1], NULL,
-                                                               10);
-                                       refresh_specified = 1;
-                                       if (cvt || rb)
-                                               cvt = 0;
-                               } else
-                                       goto done;
-                               break;
-                       case '-':
-                               namelen = i;
-                               if (!bpp_specified && !yres_specified) {
-                                       bpp = simple_strtol(&name[i+1], NULL,
-                                                           10);
-                                       bpp_specified = 1;
-                                       if (cvt || rb)
-                                               cvt = 0;
-                               } else
-                                       goto done;
-                               break;
-                       case 'x':
-                               if (!yres_specified) {
-                                       yres = simple_strtol(&name[i+1], NULL,
-                                                            10);
-                                       yres_specified = 1;
-                               } else
-                                       goto done;
-                               break;
-                       case '0' ... '9':
-                               break;
-                       case 'M':
-                               if (!yres_specified)
-                                       cvt = 1;
-                               break;
-                       case 'R':
-                               if (!cvt)
-                                       rb = 1;
-                               break;
-                       case 'm':
-                               if (!cvt)
-                                       margins = 1;
-                               break;
-                       case 'i':
-                               if (!cvt)
-                                       interlace = 1;
-                               break;
-                       default:
-                               goto done;
-                       }
-               }
-               if (i < 0 && yres_specified) {
-                       xres = simple_strtol(name, NULL, 10);
-                       res_specified = 1;
-               }
-done:
-               if (cvt) {
-                       struct fb_videomode cvt_mode;
-                       int ret;
-
-                       DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres,
-                               (refresh) ? refresh : 60,
-                               (rb) ? " reduced blanking" : "",
-                               (margins) ? " with margins" : "",
-                               (interlace) ? " interlaced" : "");
-
-                       memset(&cvt_mode, 0, sizeof(cvt_mode));
-                       cvt_mode.xres = xres;
-                       cvt_mode.yres = yres;
-                       cvt_mode.refresh = (refresh) ? refresh : 60;
-
-                       if (interlace)
-                               cvt_mode.vmode |= FB_VMODE_INTERLACED;
-                       else
-                               cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
-
-                       ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
-
-                       if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
-                               DPRINTK("modedb CVT: CVT mode ok\n");
-                               return 1;
-                       }
-
-                       DPRINTK("CVT mode invalid, getting mode from database\n");
-               }
-
-               DPRINTK("Trying specified video mode%s %ix%i\n",
-                       refresh_specified ? "" : " (ignoring refresh rate)",
-                       xres, yres);
-
-               if (!refresh_specified) {
-                       /*
-                        * If the caller has provided a custom mode database and
-                        * a valid monspecs structure, we look for the mode with
-                        * the highest refresh rate.  Otherwise we play it safe
-                        * it and try to find a mode with a refresh rate closest
-                        * to the standard 60 Hz.
-                        */
-                       if (db != modedb &&
-                           info->monspecs.vfmin && info->monspecs.vfmax &&
-                           info->monspecs.hfmin && info->monspecs.hfmax &&
-                           info->monspecs.dclkmax) {
-                               refresh = 1000;
-                       } else {
-                               refresh = 60;
-                       }
-               }
-
-               diff = -1;
-               best = -1;
-               for (i = 0; i < dbsize; i++) {
-                       if ((name_matches(db[i], name, namelen) ||
-                            (res_specified && res_matches(db[i], xres, yres))) &&
-                           !fb_try_mode(var, info, &db[i], bpp)) {
-                               if (refresh_specified && db[i].refresh == refresh)
-                                       return 1;
-
-                               if (abs(db[i].refresh - refresh) < diff) {
-                                       diff = abs(db[i].refresh - refresh);
-                                       best = i;
-                               }
-                       }
-               }
-               if (best != -1) {
-                       fb_try_mode(var, info, &db[best], bpp);
-                       return (refresh_specified) ? 2 : 1;
-               }
-
-               diff = 2 * (xres + yres);
-               best = -1;
-               DPRINTK("Trying best-fit modes\n");
-               for (i = 0; i < dbsize; i++) {
-                       DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
-                       if (!fb_try_mode(var, info, &db[i], bpp)) {
-                               tdiff = abs(db[i].xres - xres) +
-                                       abs(db[i].yres - yres);
-
-                               /*
-                                * Penalize modes with resolutions smaller
-                                * than requested.
-                                */
-                               if (xres > db[i].xres || yres > db[i].yres)
-                                       tdiff += xres + yres;
-
-                               if (diff > tdiff) {
-                                       diff = tdiff;
-                                       best = i;
-                               }
-                       }
-               }
-               if (best != -1) {
-                       fb_try_mode(var, info, &db[best], bpp);
-                       return 5;
-               }
-       }
-
-       DPRINTK("Trying default video mode\n");
-       if (!fb_try_mode(var, info, default_mode, default_bpp))
-               return 3;
-
-       DPRINTK("Trying all modes\n");
-       for (i = 0; i < dbsize; i++)
-               if (!fb_try_mode(var, info, &db[i], default_bpp))
-                       return 4;
-
-       DPRINTK("No valid mode found\n");
-       return 0;
-}
-
-/**
- * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode
- * @mode: pointer to struct fb_videomode
- * @var: pointer to struct fb_var_screeninfo
- */
-void fb_var_to_videomode(struct fb_videomode *mode,
-                        const struct fb_var_screeninfo *var)
-{
-       u32 pixclock, hfreq, htotal, vtotal;
-
-       mode->name = NULL;
-       mode->xres = var->xres;
-       mode->yres = var->yres;
-       mode->pixclock = var->pixclock;
-       mode->hsync_len = var->hsync_len;
-       mode->vsync_len = var->vsync_len;
-       mode->left_margin = var->left_margin;
-       mode->right_margin = var->right_margin;
-       mode->upper_margin = var->upper_margin;
-       mode->lower_margin = var->lower_margin;
-       mode->sync = var->sync;
-       mode->vmode = var->vmode & FB_VMODE_MASK;
-       mode->flag = FB_MODE_IS_FROM_VAR;
-       mode->refresh = 0;
-
-       if (!var->pixclock)
-               return;
-
-       pixclock = PICOS2KHZ(var->pixclock) * 1000;
-
-       htotal = var->xres + var->right_margin + var->hsync_len +
-               var->left_margin;
-       vtotal = var->yres + var->lower_margin + var->vsync_len +
-               var->upper_margin;
-
-       if (var->vmode & FB_VMODE_INTERLACED)
-               vtotal /= 2;
-       if (var->vmode & FB_VMODE_DOUBLE)
-               vtotal *= 2;
-
-       hfreq = pixclock/htotal;
-       mode->refresh = hfreq/vtotal;
-}
-
-/**
- * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo
- * @var: pointer to struct fb_var_screeninfo
- * @mode: pointer to struct fb_videomode
- */
-void fb_videomode_to_var(struct fb_var_screeninfo *var,
-                        const struct fb_videomode *mode)
-{
-       var->xres = mode->xres;
-       var->yres = mode->yres;
-       var->xres_virtual = mode->xres;
-       var->yres_virtual = mode->yres;
-       var->xoffset = 0;
-       var->yoffset = 0;
-       var->pixclock = mode->pixclock;
-       var->left_margin = mode->left_margin;
-       var->right_margin = mode->right_margin;
-       var->upper_margin = mode->upper_margin;
-       var->lower_margin = mode->lower_margin;
-       var->hsync_len = mode->hsync_len;
-       var->vsync_len = mode->vsync_len;
-       var->sync = mode->sync;
-       var->vmode = mode->vmode & FB_VMODE_MASK;
-}
-
-/**
- * fb_mode_is_equal - compare 2 videomodes
- * @mode1: first videomode
- * @mode2: second videomode
- *
- * RETURNS:
- * 1 if equal, 0 if not
- */
-int fb_mode_is_equal(const struct fb_videomode *mode1,
-                    const struct fb_videomode *mode2)
-{
-       return (mode1->xres         == mode2->xres &&
-               mode1->yres         == mode2->yres &&
-               mode1->pixclock     == mode2->pixclock &&
-               mode1->hsync_len    == mode2->hsync_len &&
-               mode1->vsync_len    == mode2->vsync_len &&
-               mode1->left_margin  == mode2->left_margin &&
-               mode1->right_margin == mode2->right_margin &&
-               mode1->upper_margin == mode2->upper_margin &&
-               mode1->lower_margin == mode2->lower_margin &&
-               mode1->sync         == mode2->sync &&
-               mode1->vmode        == mode2->vmode);
-}
-
-/**
- * fb_find_best_mode - find best matching videomode
- * @var: pointer to struct fb_var_screeninfo
- * @head: pointer to struct list_head of modelist
- *
- * RETURNS:
- * struct fb_videomode, NULL if none found
- *
- * IMPORTANT:
- * This function assumes that all modelist entries in
- * info->modelist are valid.
- *
- * NOTES:
- * Finds best matching videomode which has an equal or greater dimension than
- * var->xres and var->yres.  If more than 1 videomode is found, will return
- * the videomode with the highest refresh rate
- */
-const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var,
-                                            struct list_head *head)
-{
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       struct fb_videomode *mode, *best = NULL;
-       u32 diff = -1;
-
-       list_for_each(pos, head) {
-               u32 d;
-
-               modelist = list_entry(pos, struct fb_modelist, list);
-               mode = &modelist->mode;
-
-               if (mode->xres >= var->xres && mode->yres >= var->yres) {
-                       d = (mode->xres - var->xres) +
-                               (mode->yres - var->yres);
-                       if (diff > d) {
-                               diff = d;
-                               best = mode;
-                       } else if (diff == d && best &&
-                                  mode->refresh > best->refresh)
-                               best = mode;
-               }
-       }
-       return best;
-}
-
-/**
- * fb_find_nearest_mode - find closest videomode
- *
- * @mode: pointer to struct fb_videomode
- * @head: pointer to modelist
- *
- * Finds best matching videomode, smaller or greater in dimension.
- * If more than 1 videomode is found, will return the videomode with
- * the closest refresh rate.
- */
-const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode,
-                                               struct list_head *head)
-{
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       struct fb_videomode *cmode, *best = NULL;
-       u32 diff = -1, diff_refresh = -1;
-
-       list_for_each(pos, head) {
-               u32 d;
-
-               modelist = list_entry(pos, struct fb_modelist, list);
-               cmode = &modelist->mode;
-
-               d = abs(cmode->xres - mode->xres) +
-                       abs(cmode->yres - mode->yres);
-               if (diff > d) {
-                       diff = d;
-                       diff_refresh = abs(cmode->refresh - mode->refresh);
-                       best = cmode;
-               } else if (diff == d) {
-                       d = abs(cmode->refresh - mode->refresh);
-                       if (diff_refresh > d) {
-                               diff_refresh = d;
-                               best = cmode;
-                       }
-               }
-       }
-
-       return best;
-}
-
-/**
- * fb_match_mode - find a videomode which exactly matches the timings in var
- * @var: pointer to struct fb_var_screeninfo
- * @head: pointer to struct list_head of modelist
- *
- * RETURNS:
- * struct fb_videomode, NULL if none found
- */
-const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
-                                        struct list_head *head)
-{
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       struct fb_videomode *m, mode;
-
-       fb_var_to_videomode(&mode, var);
-       list_for_each(pos, head) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               m = &modelist->mode;
-               if (fb_mode_is_equal(m, &mode))
-                       return m;
-       }
-       return NULL;
-}
-
-/**
- * fb_add_videomode - adds videomode entry to modelist
- * @mode: videomode to add
- * @head: struct list_head of modelist
- *
- * NOTES:
- * Will only add unmatched mode entries
- */
-int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
-{
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       struct fb_videomode *m;
-       int found = 0;
-
-       list_for_each(pos, head) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               m = &modelist->mode;
-               if (fb_mode_is_equal(m, mode)) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found) {
-               modelist = kmalloc(sizeof(struct fb_modelist),
-                                                 GFP_KERNEL);
-
-               if (!modelist)
-                       return -ENOMEM;
-               modelist->mode = *mode;
-               list_add(&modelist->list, head);
-       }
-       return 0;
-}
-
-/**
- * fb_delete_videomode - removed videomode entry from modelist
- * @mode: videomode to remove
- * @head: struct list_head of modelist
- *
- * NOTES:
- * Will remove all matching mode entries
- */
-void fb_delete_videomode(const struct fb_videomode *mode,
-                        struct list_head *head)
-{
-       struct list_head *pos, *n;
-       struct fb_modelist *modelist;
-       struct fb_videomode *m;
-
-       list_for_each_safe(pos, n, head) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               m = &modelist->mode;
-               if (fb_mode_is_equal(m, mode)) {
-                       list_del(pos);
-                       kfree(pos);
-               }
-       }
-}
-
-/**
- * fb_destroy_modelist - destroy modelist
- * @head: struct list_head of modelist
- */
-void fb_destroy_modelist(struct list_head *head)
-{
-       struct list_head *pos, *n;
-
-       list_for_each_safe(pos, n, head) {
-               list_del(pos);
-               kfree(pos);
-       }
-}
-EXPORT_SYMBOL_GPL(fb_destroy_modelist);
-
-/**
- * fb_videomode_to_modelist - convert mode array to mode list
- * @modedb: array of struct fb_videomode
- * @num: number of entries in array
- * @head: struct list_head of modelist
- */
-void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num,
-                             struct list_head *head)
-{
-       int i;
-
-       INIT_LIST_HEAD(head);
-
-       for (i = 0; i < num; i++) {
-               if (fb_add_videomode(&modedb[i], head))
-                       return;
-       }
-}
-
-const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs,
-                                               struct list_head *head)
-{
-       struct list_head *pos;
-       struct fb_modelist *modelist;
-       const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
-       int first = 0;
-
-       if (!head->prev || !head->next || list_empty(head))
-               goto finished;
-
-       /* get the first detailed mode and the very first mode */
-       list_for_each(pos, head) {
-               modelist = list_entry(pos, struct fb_modelist, list);
-               m = &modelist->mode;
-
-               if (!first) {
-                       m1 = m;
-                       first = 1;
-               }
-
-               if (m->flag & FB_MODE_IS_FIRST) {
-                       md = m;
-                       break;
-               }
-       }
-
-       /* first detailed timing is preferred */
-       if (specs->misc & FB_MISC_1ST_DETAIL) {
-               best = md;
-               goto finished;
-       }
-
-       /* find best mode based on display width and height */
-       if (specs->max_x && specs->max_y) {
-               struct fb_var_screeninfo var;
-
-               memset(&var, 0, sizeof(struct fb_var_screeninfo));
-               var.xres = (specs->max_x * 7200)/254;
-               var.yres = (specs->max_y * 7200)/254;
-               m = fb_find_best_mode(&var, head);
-               if (m) {
-                       best = m;
-                       goto finished;
-               }
-       }
-
-       /* use first detailed mode */
-       if (md) {
-               best = md;
-               goto finished;
-       }
-
-       /* last resort, use the very first mode */
-       best = m1;
-finished:
-       return best;
-}
-EXPORT_SYMBOL(fb_find_best_display);
-
-EXPORT_SYMBOL(fb_videomode_to_var);
-EXPORT_SYMBOL(fb_var_to_videomode);
-EXPORT_SYMBOL(fb_mode_is_equal);
-EXPORT_SYMBOL(fb_add_videomode);
-EXPORT_SYMBOL(fb_match_mode);
-EXPORT_SYMBOL(fb_find_best_mode);
-EXPORT_SYMBOL(fb_find_nearest_mode);
-EXPORT_SYMBOL(fb_videomode_to_modelist);
-EXPORT_SYMBOL(fb_find_mode);
-EXPORT_SYMBOL(fb_find_mode_cvt);
diff --git a/drivers/video/fbdev/svgalib.c b/drivers/video/fbdev/svgalib.c
deleted file mode 100644 (file)
index 9e01322..0000000
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Common utility functions for VGA-based graphics cards.
- *
- * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
- *
- * 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.
- *
- * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <linux/svga.h>
-#include <asm/types.h>
-#include <asm/io.h>
-
-
-/* Write a CRT register value spread across multiple registers */
-void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
-{
-       u8 regval, bitval, bitnum;
-
-       while (regset->regnum != VGA_REGSET_END_VAL) {
-               regval = vga_rcrt(regbase, regset->regnum);
-               bitnum = regset->lowbit;
-               while (bitnum <= regset->highbit) {
-                       bitval = 1 << bitnum;
-                       regval = regval & ~bitval;
-                       if (value & 1) regval = regval | bitval;
-                       bitnum ++;
-                       value = value >> 1;
-               }
-               vga_wcrt(regbase, regset->regnum, regval);
-               regset ++;
-       }
-}
-
-/* Write a sequencer register value spread across multiple registers */
-void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
-{
-       u8 regval, bitval, bitnum;
-
-       while (regset->regnum != VGA_REGSET_END_VAL) {
-               regval = vga_rseq(regbase, regset->regnum);
-               bitnum = regset->lowbit;
-               while (bitnum <= regset->highbit) {
-                       bitval = 1 << bitnum;
-                       regval = regval & ~bitval;
-                       if (value & 1) regval = regval | bitval;
-                       bitnum ++;
-                       value = value >> 1;
-               }
-               vga_wseq(regbase, regset->regnum, regval);
-               regset ++;
-       }
-}
-
-static unsigned int svga_regset_size(const struct vga_regset *regset)
-{
-       u8 count = 0;
-
-       while (regset->regnum != VGA_REGSET_END_VAL) {
-               count += regset->highbit - regset->lowbit + 1;
-               regset ++;
-       }
-       return 1 << count;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/* Set graphics controller registers to sane values */
-void svga_set_default_gfx_regs(void __iomem *regbase)
-{
-       /* All standard GFX registers (GR00 - GR08) */
-       vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00);
-       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00);
-       vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00);
-       vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00);
-       vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00);
-       vga_wgfx(regbase, VGA_GFX_MODE, 0x00);
-/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */
-/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */
-       vga_wgfx(regbase, VGA_GFX_MISC, 0x05);
-/*     vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F);
-       vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF);
-}
-
-/* Set attribute controller registers to sane values */
-void svga_set_default_atc_regs(void __iomem *regbase)
-{
-       u8 count;
-
-       vga_r(regbase, 0x3DA);
-       vga_w(regbase, VGA_ATT_W, 0x00);
-
-       /* All standard ATC registers (AR00 - AR14) */
-       for (count = 0; count <= 0xF; count ++)
-               svga_wattr(regbase, count, count);
-
-       svga_wattr(regbase, VGA_ATC_MODE, 0x01);
-/*     svga_wattr(regbase, VGA_ATC_MODE, 0x41); */
-       svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00);
-       svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F);
-       svga_wattr(regbase, VGA_ATC_PEL, 0x00);
-       svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00);
-
-       vga_r(regbase, 0x3DA);
-       vga_w(regbase, VGA_ATT_W, 0x20);
-}
-
-/* Set sequencer registers to sane values */
-void svga_set_default_seq_regs(void __iomem *regbase)
-{
-       /* Standard sequencer registers (SR01 - SR04), SR00 is not set */
-       vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
-       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
-       vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
-/*     vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
-       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
-}
-
-/* Set CRTC registers to sane values */
-void svga_set_default_crt_regs(void __iomem *regbase)
-{
-       /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
-       svga_wcrt_mask(regbase, 0x03, 0x80, 0x80);      /* Enable vertical retrace EVRA */
-       vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
-       svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F);
-       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
-       vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3);
-}
-
-void svga_set_textmode_vga_regs(void __iomem *regbase)
-{
-       /* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */
-       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);
-       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03);
-
-       vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */
-       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f);
-       svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f);
-
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d);
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e);
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00);
-       vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00);
-
-       vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */
-       vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */
-       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00);
-
-       vga_r(regbase, 0x3DA);
-       vga_w(regbase, VGA_ATT_W, 0x00);
-
-       svga_wattr(regbase, 0x10, 0x0C);                        /* Attribute Mode Control Register - text mode, blinking and line graphics */
-       svga_wattr(regbase, 0x13, 0x08);                        /* Horizontal Pixel Panning Register  */
-
-       vga_r(regbase, 0x3DA);
-       vga_w(regbase, VGA_ATT_W, 0x20);
-}
-
-#if 0
-void svga_dump_var(struct fb_var_screeninfo *var, int node)
-{
-       pr_debug("fb%d: var.vmode         : 0x%X\n", node, var->vmode);
-       pr_debug("fb%d: var.xres          : %d\n", node, var->xres);
-       pr_debug("fb%d: var.yres          : %d\n", node, var->yres);
-       pr_debug("fb%d: var.bits_per_pixel: %d\n", node, var->bits_per_pixel);
-       pr_debug("fb%d: var.xres_virtual  : %d\n", node, var->xres_virtual);
-       pr_debug("fb%d: var.yres_virtual  : %d\n", node, var->yres_virtual);
-       pr_debug("fb%d: var.left_margin   : %d\n", node, var->left_margin);
-       pr_debug("fb%d: var.right_margin  : %d\n", node, var->right_margin);
-       pr_debug("fb%d: var.upper_margin  : %d\n", node, var->upper_margin);
-       pr_debug("fb%d: var.lower_margin  : %d\n", node, var->lower_margin);
-       pr_debug("fb%d: var.hsync_len     : %d\n", node, var->hsync_len);
-       pr_debug("fb%d: var.vsync_len     : %d\n", node, var->vsync_len);
-       pr_debug("fb%d: var.sync          : 0x%X\n", node, var->sync);
-       pr_debug("fb%d: var.pixclock      : %d\n\n", node, var->pixclock);
-}
-#endif  /*  0  */
-
-
-/* ------------------------------------------------------------------------- */
-
-
-void svga_settile(struct fb_info *info, struct fb_tilemap *map)
-{
-       const u8 *font = map->data;
-       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
-       int i, c;
-
-       if ((map->width != 8) || (map->height != 16) ||
-           (map->depth != 1) || (map->length != 256)) {
-               fb_err(info, "unsupported font parameters: width %d, height %d, depth %d, length %d\n",
-                      map->width, map->height, map->depth, map->length);
-               return;
-       }
-
-       fb += 2;
-       for (c = 0; c < map->length; c++) {
-               for (i = 0; i < map->height; i++) {
-                       fb_writeb(font[i], fb + i * 4);
-//                     fb[i * 4] = font[i];
-               }
-               fb += 128;
-               font += map->height;
-       }
-}
-
-/* Copy area in text (tileblit) mode */
-void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
-{
-       int dx, dy;
-       /*  colstride is halved in this function because u16 are used */
-       int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
-       int rowstride = colstride * (info->var.xres_virtual / 8);
-       u16 __iomem *fb = (u16 __iomem *) info->screen_base;
-       u16 __iomem *src, *dst;
-
-       if ((area->sy > area->dy) ||
-           ((area->sy == area->dy) && (area->sx > area->dx))) {
-               src = fb + area->sx * colstride + area->sy * rowstride;
-               dst = fb + area->dx * colstride + area->dy * rowstride;
-           } else {
-               src = fb + (area->sx + area->width - 1) * colstride
-                        + (area->sy + area->height - 1) * rowstride;
-               dst = fb + (area->dx + area->width - 1) * colstride
-                        + (area->dy + area->height - 1) * rowstride;
-
-               colstride = -colstride;
-               rowstride = -rowstride;
-           }
-
-       for (dy = 0; dy < area->height; dy++) {
-               u16 __iomem *src2 = src;
-               u16 __iomem *dst2 = dst;
-               for (dx = 0; dx < area->width; dx++) {
-                       fb_writew(fb_readw(src2), dst2);
-//                     *dst2 = *src2;
-                       src2 += colstride;
-                       dst2 += colstride;
-               }
-               src += rowstride;
-               dst += rowstride;
-       }
-}
-
-/* Fill area in text (tileblit) mode */
-void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)
-{
-       int dx, dy;
-       int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
-       int rowstride = colstride * (info->var.xres_virtual / 8);
-       int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
-       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
-       fb += rect->sx * colstride + rect->sy * rowstride;
-
-       for (dy = 0; dy < rect->height; dy++) {
-               u8 __iomem *fb2 = fb;
-               for (dx = 0; dx < rect->width; dx++) {
-                       fb_writeb(rect->index, fb2);
-                       fb_writeb(attr, fb2 + 1);
-                       fb2 += colstride;
-               }
-               fb += rowstride;
-       }
-}
-
-/* Write text in text (tileblit) mode */
-void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
-{
-       int dx, dy, i;
-       int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
-       int rowstride = colstride * (info->var.xres_virtual / 8);
-       int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
-       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
-       fb += blit->sx * colstride + blit->sy * rowstride;
-
-       i=0;
-       for (dy=0; dy < blit->height; dy ++) {
-               u8 __iomem *fb2 = fb;
-               for (dx = 0; dx < blit->width; dx ++) {
-                       fb_writeb(blit->indices[i], fb2);
-                       fb_writeb(attr, fb2 + 1);
-                       fb2 += colstride;
-                       i ++;
-                       if (i == blit->length) return;
-               }
-               fb += rowstride;
-       }
-
-}
-
-/* Set cursor in text (tileblit) mode */
-void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor)
-{
-       u8 cs = 0x0d;
-       u8 ce = 0x0e;
-       u16 pos =  cursor->sx + (info->var.xoffset /  8)
-               + (cursor->sy + (info->var.yoffset / 16))
-                  * (info->var.xres_virtual / 8);
-
-       if (! cursor -> mode)
-               return;
-
-       svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */
-
-       if (cursor -> shape == FB_TILE_CURSOR_NONE)
-               return;
-
-       switch (cursor -> shape) {
-       case FB_TILE_CURSOR_UNDERLINE:
-               cs = 0x0d;
-               break;
-       case FB_TILE_CURSOR_LOWER_THIRD:
-               cs = 0x09;
-               break;
-       case FB_TILE_CURSOR_LOWER_HALF:
-               cs = 0x07;
-               break;
-       case FB_TILE_CURSOR_TWO_THIRDS:
-               cs = 0x05;
-               break;
-       case FB_TILE_CURSOR_BLOCK:
-               cs = 0x01;
-               break;
-       }
-
-       /* set cursor position */
-       vga_wcrt(regbase, 0x0E, pos >> 8);
-       vga_wcrt(regbase, 0x0F, pos & 0xFF);
-
-       vga_wcrt(regbase, 0x0B, ce); /* set cursor end */
-       vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */
-}
-
-int svga_get_tilemax(struct fb_info *info)
-{
-       return 256;
-}
-
-/* Get capabilities of accelerator based on the mode */
-
-void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
-                  struct fb_var_screeninfo *var)
-{
-       if (var->bits_per_pixel == 0) {
-               /* can only support 256 8x16 bitmap */
-               caps->x = 1 << (8 - 1);
-               caps->y = 1 << (16 - 1);
-               caps->len = 256;
-       } else {
-               caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
-               caps->y = ~(u32)0;
-               caps->len = ~(u32)0;
-       }
-}
-EXPORT_SYMBOL(svga_get_caps);
-
-/* ------------------------------------------------------------------------- */
-
-
-/*
- *  Compute PLL settings (M, N, R)
- *  F_VCO = (F_BASE * M) / N
- *  F_OUT = F_VCO / (2^R)
- */
-
-static inline u32 abs_diff(u32 a, u32 b)
-{
-       return (a > b) ? (a - b) : (b - a);
-}
-
-int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)
-{
-       u16 am, an, ar;
-       u32 f_vco, f_current, delta_current, delta_best;
-
-       pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);
-
-       ar = pll->r_max;
-       f_vco = f_wanted << ar;
-
-       /* overflow check */
-       if ((f_vco >> ar) != f_wanted)
-               return -EINVAL;
-
-       /* It is usually better to have greater VCO clock
-          because of better frequency stability.
-          So first try r_max, then r smaller. */
-       while ((ar > pll->r_min) && (f_vco > pll->f_vco_max)) {
-               ar--;
-               f_vco = f_vco >> 1;
-       }
-
-       /* VCO bounds check */
-       if ((f_vco < pll->f_vco_min) || (f_vco > pll->f_vco_max))
-               return -EINVAL;
-
-       delta_best = 0xFFFFFFFF;
-       *m = 0;
-       *n = 0;
-       *r = ar;
-
-       am = pll->m_min;
-       an = pll->n_min;
-
-       while ((am <= pll->m_max) && (an <= pll->n_max)) {
-               f_current = (pll->f_base * am) / an;
-               delta_current = abs_diff (f_current, f_vco);
-
-               if (delta_current < delta_best) {
-                       delta_best = delta_current;
-                       *m = am;
-                       *n = an;
-               }
-
-               if (f_current <= f_vco) {
-                       am ++;
-               } else {
-                       an ++;
-               }
-       }
-
-       f_current = (pll->f_base * *m) / *n;
-       pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);
-       pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/* Check CRT timing values */
-int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
-{
-       u32 value;
-
-       var->xres         = (var->xres+7)&~7;
-       var->left_margin  = (var->left_margin+7)&~7;
-       var->right_margin = (var->right_margin+7)&~7;
-       var->hsync_len    = (var->hsync_len+7)&~7;
-
-       /* Check horizontal total */
-       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
-       if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))
-               return -EINVAL;
-
-       /* Check horizontal display and blank start */
-       value = var->xres;
-       if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))
-               return -EINVAL;
-       if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))
-               return -EINVAL;
-
-       /* Check horizontal sync start */
-       value = var->xres + var->right_margin;
-       if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))
-               return -EINVAL;
-
-       /* Check horizontal blank end (or length) */
-       value = var->left_margin + var->right_margin + var->hsync_len;
-       if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))
-               return -EINVAL;
-
-       /* Check horizontal sync end (or length) */
-       value = var->hsync_len;
-       if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))
-               return -EINVAL;
-
-       /* Check vertical total */
-       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
-       if ((value - 1) >= svga_regset_size(tm->v_total_regs))
-               return -EINVAL;
-
-       /* Check vertical display and blank start */
-       value = var->yres;
-       if ((value - 1) >= svga_regset_size(tm->v_display_regs))
-               return -EINVAL;
-       if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs))
-               return -EINVAL;
-
-       /* Check vertical sync start */
-       value = var->yres + var->lower_margin;
-       if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs))
-               return -EINVAL;
-
-       /* Check vertical blank end (or length) */
-       value = var->upper_margin + var->lower_margin + var->vsync_len;
-       if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))
-               return -EINVAL;
-
-       /* Check vertical sync end  (or length) */
-       value = var->vsync_len;
-       if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))
-               return -EINVAL;
-
-       return 0;
-}
-
-/* Set CRT timing registers */
-void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
-                     struct fb_var_screeninfo *var,
-                     u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
-{
-       u8 regval;
-       u32 value;
-
-       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal total      : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5);
-
-       value = var->xres;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal display    : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1);
-
-       value = var->xres;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal blank start: %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder);
-
-       value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal blank end  : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder);
-
-       value = var->xres + var->right_margin;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal sync start : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8));
-
-       value = var->xres + var->right_margin + var->hsync_len;
-       value = (value * hmul) / hdiv;
-       pr_debug("fb%d: horizontal sync end   : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8));
-
-       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical total        : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_total_regs, value - 2);
-
-       value = var->yres;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical display      : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_display_regs, value - 1);
-
-       value = var->yres;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical blank start  : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_blank_start_regs, value);
-
-       value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical blank end    : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2);
-
-       value = var->yres + var->lower_margin;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical sync start   : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_sync_start_regs, value);
-
-       value = var->yres + var->lower_margin + var->vsync_len;
-       value = (value * vmul) / vdiv;
-       pr_debug("fb%d: vertical sync end     : %d\n", node, value);
-       svga_wcrt_multi(regbase, tm->v_sync_end_regs, value);
-
-       /* Set horizontal and vertical sync pulse polarity in misc register */
-
-       regval = vga_r(regbase, VGA_MIS_R);
-       if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
-               pr_debug("fb%d: positive horizontal sync\n", node);
-               regval = regval & ~0x80;
-       } else {
-               pr_debug("fb%d: negative horizontal sync\n", node);
-               regval = regval | 0x80;
-       }
-       if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
-               pr_debug("fb%d: positive vertical sync\n", node);
-               regval = regval & ~0x40;
-       } else {
-               pr_debug("fb%d: negative vertical sync\n\n", node);
-               regval = regval | 0x40;
-       }
-       vga_w(regbase, VGA_MIS_W, regval);
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-static inline int match_format(const struct svga_fb_format *frm,
-                              struct fb_var_screeninfo *var)
-{
-       int i = 0;
-       int stored = -EINVAL;
-
-       while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
-       {
-               if ((var->bits_per_pixel == frm->bits_per_pixel) &&
-                   (var->red.length     <= frm->red.length)     &&
-                   (var->green.length   <= frm->green.length)   &&
-                   (var->blue.length    <= frm->blue.length)    &&
-                   (var->transp.length  <= frm->transp.length)  &&
-                   (var->nonstd         == frm->nonstd))
-                       return i;
-               if (var->bits_per_pixel == frm->bits_per_pixel)
-                       stored = i;
-               i++;
-               frm++;
-       }
-       return stored;
-}
-
-int svga_match_format(const struct svga_fb_format *frm,
-                     struct fb_var_screeninfo *var,
-                     struct fb_fix_screeninfo *fix)
-{
-       int i = match_format(frm, var);
-
-       if (i >= 0) {
-               var->bits_per_pixel = frm[i].bits_per_pixel;
-               var->red            = frm[i].red;
-               var->green          = frm[i].green;
-               var->blue           = frm[i].blue;
-               var->transp         = frm[i].transp;
-               var->nonstd         = frm[i].nonstd;
-               if (fix != NULL) {
-                       fix->type      = frm[i].type;
-                       fix->type_aux  = frm[i].type_aux;
-                       fix->visual    = frm[i].visual;
-                       fix->xpanstep  = frm[i].xpanstep;
-               }
-       }
-
-       return i;
-}
-
-
-EXPORT_SYMBOL(svga_wcrt_multi);
-EXPORT_SYMBOL(svga_wseq_multi);
-
-EXPORT_SYMBOL(svga_set_default_gfx_regs);
-EXPORT_SYMBOL(svga_set_default_atc_regs);
-EXPORT_SYMBOL(svga_set_default_seq_regs);
-EXPORT_SYMBOL(svga_set_default_crt_regs);
-EXPORT_SYMBOL(svga_set_textmode_vga_regs);
-
-EXPORT_SYMBOL(svga_settile);
-EXPORT_SYMBOL(svga_tilecopy);
-EXPORT_SYMBOL(svga_tilefill);
-EXPORT_SYMBOL(svga_tileblit);
-EXPORT_SYMBOL(svga_tilecursor);
-EXPORT_SYMBOL(svga_get_tilemax);
-
-EXPORT_SYMBOL(svga_compute_pll);
-EXPORT_SYMBOL(svga_check_timings);
-EXPORT_SYMBOL(svga_set_timings);
-EXPORT_SYMBOL(svga_match_format);
-
-MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>");
-MODULE_DESCRIPTION("Common utility functions for VGA-based graphics cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/syscopyarea.c b/drivers/video/fbdev/syscopyarea.c
deleted file mode 100644 (file)
index 844a32f..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- *  Generic Bit Block Transfer for frame buffers located in system RAM with
- *  packed pixels of any depth.
- *
- *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
- *  on Geert Uytterhoeven's copyarea routine)
- *
- *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
- *
- *  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.
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-#include <asm/io.h>
-#include "fb_draw.h"
-
-    /*
-     *  Generic bitwise copy algorithm
-     */
-
-static void
-bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
-               const unsigned long *src, int src_idx, int bits, unsigned n)
-{
-       unsigned long first, last;
-       int const shift = dst_idx-src_idx;
-       int left, right;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (!shift) {
-               /* Same alignment for source and dest */
-               if (dst_idx+n <= bits) {
-                       /* Single word */
-                       if (last)
-                               first &= last;
-                       *dst = comp(*src, *dst, first);
-               } else {
-                       /* Multiple destination words */
-                       /* Leading bits */
-                       if (first != ~0UL) {
-                               *dst = comp(*src, *dst, first);
-                               dst++;
-                               src++;
-                               n -= bits - dst_idx;
-                       }
-
-                       /* Main chunk */
-                       n /= bits;
-                       while (n >= 8) {
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               n -= 8;
-                       }
-                       while (n--)
-                               *dst++ = *src++;
-
-                       /* Trailing bits */
-                       if (last)
-                               *dst = comp(*src, *dst, last);
-               }
-       } else {
-               unsigned long d0, d1;
-               int m;
-
-               /* Different alignment for source and dest */
-               right = shift & (bits - 1);
-               left = -shift & (bits - 1);
-
-               if (dst_idx+n <= bits) {
-                       /* Single destination word */
-                       if (last)
-                               first &= last;
-                       if (shift > 0) {
-                               /* Single source word */
-                               *dst = comp(*src >> right, *dst, first);
-                       } else if (src_idx+n <= bits) {
-                               /* Single source word */
-                               *dst = comp(*src << left, *dst, first);
-                       } else {
-                               /* 2 source words */
-                               d0 = *src++;
-                               d1 = *src;
-                               *dst = comp(d0 << left | d1 >> right, *dst,
-                                           first);
-                       }
-               } else {
-                       /* Multiple destination words */
-                       /** We must always remember the last value read,
-                           because in case SRC and DST overlap bitwise (e.g.
-                           when moving just one pixel in 1bpp), we always
-                           collect one full long for DST and that might
-                           overlap with the current long from SRC. We store
-                           this value in 'd0'. */
-                       d0 = *src++;
-                       /* Leading bits */
-                       if (shift > 0) {
-                               /* Single source word */
-                               *dst = comp(d0 >> right, *dst, first);
-                               dst++;
-                               n -= bits - dst_idx;
-                       } else {
-                               /* 2 source words */
-                               d1 = *src++;
-                               *dst = comp(d0 << left | *dst >> right, *dst, first);
-                               d0 = d1;
-                               dst++;
-                               n -= bits - dst_idx;
-                       }
-
-                       /* Main chunk */
-                       m = n % bits;
-                       n /= bits;
-                       while (n >= 4) {
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                       }
-
-                       /* Trailing bits */
-                       if (last) {
-                               if (m <= right) {
-                                       /* Single source word */
-                                       *dst = comp(d0 << left, *dst, last);
-                               } else {
-                                       /* 2 source words */
-                                       d1 = *src;
-                                       *dst = comp(d0 << left | d1 >> right,
-                                                   *dst, last);
-                               }
-                       }
-               }
-       }
-}
-
-    /*
-     *  Generic bitwise copy algorithm, operating backward
-     */
-
-static void
-bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
-               const unsigned long *src, int src_idx, int bits, unsigned n)
-{
-       unsigned long first, last;
-       int shift;
-
-       dst += (n-1)/bits;
-       src += (n-1)/bits;
-       if ((n-1) % bits) {
-               dst_idx += (n-1) % bits;
-               dst += dst_idx >> (ffs(bits) - 1);
-               dst_idx &= bits - 1;
-               src_idx += (n-1) % bits;
-               src += src_idx >> (ffs(bits) - 1);
-               src_idx &= bits - 1;
-       }
-
-       shift = dst_idx-src_idx;
-
-       first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
-       last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
-
-       if (!shift) {
-               /* Same alignment for source and dest */
-               if ((unsigned long)dst_idx+1 >= n) {
-                       /* Single word */
-                       if (last)
-                               first &= last;
-                       *dst = comp(*src, *dst, first);
-               } else {
-                       /* Multiple destination words */
-
-                       /* Leading bits */
-                       if (first != ~0UL) {
-                               *dst = comp(*src, *dst, first);
-                               dst--;
-                               src--;
-                               n -= dst_idx+1;
-                       }
-
-                       /* Main chunk */
-                       n /= bits;
-                       while (n >= 8) {
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               n -= 8;
-                       }
-                       while (n--)
-                               *dst-- = *src--;
-                       /* Trailing bits */
-                       if (last)
-                               *dst = comp(*src, *dst, last);
-               }
-       } else {
-               /* Different alignment for source and dest */
-
-               int const left = -shift & (bits-1);
-               int const right = shift & (bits-1);
-
-               if ((unsigned long)dst_idx+1 >= n) {
-                       /* Single destination word */
-                       if (last)
-                               first &= last;
-                       if (shift < 0) {
-                               /* Single source word */
-                               *dst = comp(*src << left, *dst, first);
-                       } else if (1+(unsigned long)src_idx >= n) {
-                               /* Single source word */
-                               *dst = comp(*src >> right, *dst, first);
-                       } else {
-                               /* 2 source words */
-                               *dst = comp(*src >> right | *(src-1) << left,
-                                           *dst, first);
-                       }
-               } else {
-                       /* Multiple destination words */
-                       /** We must always remember the last value read,
-                           because in case SRC and DST overlap bitwise (e.g.
-                           when moving just one pixel in 1bpp), we always
-                           collect one full long for DST and that might
-                           overlap with the current long from SRC. We store
-                           this value in 'd0'. */
-                       unsigned long d0, d1;
-                       int m;
-
-                       d0 = *src--;
-                       /* Leading bits */
-                       if (shift < 0) {
-                               /* Single source word */
-                               *dst = comp(d0 << left, *dst, first);
-                       } else {
-                               /* 2 source words */
-                               d1 = *src--;
-                               *dst = comp(d0 >> right | d1 << left, *dst,
-                                           first);
-                               d0 = d1;
-                       }
-                       dst--;
-                       n -= dst_idx+1;
-
-                       /* Main chunk */
-                       m = n % bits;
-                       n /= bits;
-                       while (n >= 4) {
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                       }
-
-                       /* Trailing bits */
-                       if (last) {
-                               if (m <= left) {
-                                       /* Single source word */
-                                       *dst = comp(d0 >> right, *dst, last);
-                               } else {
-                                       /* 2 source words */
-                                       d1 = *src;
-                                       *dst = comp(d0 >> right | d1 << left,
-                                                   *dst, last);
-                               }
-                       }
-               }
-       }
-}
-
-void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
-{
-       u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
-       u32 height = area->height, width = area->width;
-       unsigned long const bits_per_line = p->fix.line_length*8u;
-       unsigned long *dst = NULL, *src = NULL;
-       int bits = BITS_PER_LONG, bytes = bits >> 3;
-       int dst_idx = 0, src_idx = 0, rev_copy = 0;
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       /* if the beginning of the target area might overlap with the end of
-       the source area, be have to copy the area reverse. */
-       if ((dy == sy && dx > sx) || (dy > sy)) {
-               dy += height;
-               sy += height;
-               rev_copy = 1;
-       }
-
-       /* split the base of the framebuffer into a long-aligned address and
-          the index of the first bit */
-       dst = src = (unsigned long *)((unsigned long)p->screen_base &
-                                     ~(bytes-1));
-       dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
-       /* add offset of source and target area */
-       dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
-       src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
-
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-
-       if (rev_copy) {
-               while (height--) {
-                       dst_idx -= bits_per_line;
-                       src_idx -= bits_per_line;
-                       dst += dst_idx >> (ffs(bits) - 1);
-                       dst_idx &= (bytes - 1);
-                       src += src_idx >> (ffs(bits) - 1);
-                       src_idx &= (bytes - 1);
-                       bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
-                               width*p->var.bits_per_pixel);
-               }
-       } else {
-               while (height--) {
-                       dst += dst_idx >> (ffs(bits) - 1);
-                       dst_idx &= (bytes - 1);
-                       src += src_idx >> (ffs(bits) - 1);
-                       src_idx &= (bytes - 1);
-                       bitcpy(p, dst, dst_idx, src, src_idx, bits,
-                               width*p->var.bits_per_pixel);
-                       dst_idx += bits_per_line;
-                       src_idx += bits_per_line;
-               }
-       }
-}
-
-EXPORT_SYMBOL(sys_copyarea);
-
-MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
-MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/fbdev/sysfillrect.c b/drivers/video/fbdev/sysfillrect.c
deleted file mode 100644 (file)
index 33ee3d3..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- *  Generic fillrect for frame buffers in system RAM with packed pixels of
- *  any depth.
- *
- *  Based almost entirely from cfbfillrect.c (which is based almost entirely
- *  on Geert Uytterhoeven's fillrect routine)
- *
- *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
- *
- *  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.
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-#include "fb_draw.h"
-
-    /*
-     *  Aligned pattern fill using 32/64-bit memory accesses
-     */
-
-static void
-bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
-               unsigned long pat, unsigned n, int bits)
-{
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               /* Single word */
-               if (last)
-                       first &= last;
-               *dst = comp(pat, *dst, first);
-       } else {
-               /* Multiple destination words */
-
-               /* Leading bits */
-               if (first!= ~0UL) {
-                       *dst = comp(pat, *dst, first);
-                       dst++;
-                       n -= bits - dst_idx;
-               }
-
-               /* Main chunk */
-               n /= bits;
-               while (n >= 8) {
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       *dst++ = pat;
-                       n -= 8;
-               }
-               while (n--)
-                       *dst++ = pat;
-               /* Trailing bits */
-               if (last)
-                       *dst = comp(pat, *dst, last);
-       }
-}
-
-
-    /*
-     *  Unaligned generic pattern fill using 32/64-bit memory accesses
-     *  The pattern must have been expanded to a full 32/64-bit value
-     *  Left/right are the appropriate shifts to convert to the pattern to be
-     *  used for the next 32/64-bit word
-     */
-
-static void
-bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
-                 unsigned long pat, int left, int right, unsigned n, int bits)
-{
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               /* Single word */
-               if (last)
-                       first &= last;
-               *dst = comp(pat, *dst, first);
-       } else {
-               /* Multiple destination words */
-               /* Leading bits */
-               if (first) {
-                       *dst = comp(pat, *dst, first);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       n -= bits - dst_idx;
-               }
-
-               /* Main chunk */
-               n /= bits;
-               while (n >= 4) {
-                       *dst++ = pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ = pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ = pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ = pat;
-                       pat = pat << left | pat >> right;
-                       n -= 4;
-               }
-               while (n--) {
-                       *dst++ = pat;
-                       pat = pat << left | pat >> right;
-               }
-
-               /* Trailing bits */
-               if (last)
-                       *dst = comp(pat, *dst, last);
-       }
-}
-
-    /*
-     *  Aligned pattern invert using 32/64-bit memory accesses
-     */
-static void
-bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
-                   unsigned long pat, unsigned n, int bits)
-{
-       unsigned long val = pat;
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               /* Single word */
-               if (last)
-                       first &= last;
-               *dst = comp(*dst ^ val, *dst, first);
-       } else {
-               /* Multiple destination words */
-               /* Leading bits */
-               if (first!=0UL) {
-                       *dst = comp(*dst ^ val, *dst, first);
-                       dst++;
-                       n -= bits - dst_idx;
-               }
-
-               /* Main chunk */
-               n /= bits;
-               while (n >= 8) {
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       n -= 8;
-               }
-               while (n--)
-                       *dst++ ^= val;
-               /* Trailing bits */
-               if (last)
-                       *dst = comp(*dst ^ val, *dst, last);
-       }
-}
-
-
-    /*
-     *  Unaligned generic pattern invert using 32/64-bit memory accesses
-     *  The pattern must have been expanded to a full 32/64-bit value
-     *  Left/right are the appropriate shifts to convert to the pattern to be
-     *  used for the next 32/64-bit word
-     */
-
-static void
-bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
-                     unsigned long pat, int left, int right, unsigned n,
-                     int bits)
-{
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-       first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
-       last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
-
-       if (dst_idx+n <= bits) {
-               /* Single word */
-               if (last)
-                       first &= last;
-               *dst = comp(*dst ^ pat, *dst, first);
-       } else {
-               /* Multiple destination words */
-
-               /* Leading bits */
-               if (first != 0UL) {
-                       *dst = comp(*dst ^ pat, *dst, first);
-                       dst++;
-                       pat = pat << left | pat >> right;
-                       n -= bits - dst_idx;
-               }
-
-               /* Main chunk */
-               n /= bits;
-               while (n >= 4) {
-                       *dst++ ^= pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ ^= pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ ^= pat;
-                       pat = pat << left | pat >> right;
-                       *dst++ ^= pat;
-                       pat = pat << left | pat >> right;
-                       n -= 4;
-               }
-               while (n--) {
-                       *dst ^= pat;
-                       pat = pat << left | pat >> right;
-               }
-
-               /* Trailing bits */
-               if (last)
-                       *dst = comp(*dst ^ pat, *dst, last);
-       }
-}
-
-void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
-{
-       unsigned long pat, pat2, fg;
-       unsigned long width = rect->width, height = rect->height;
-       int bits = BITS_PER_LONG, bytes = bits >> 3;
-       u32 bpp = p->var.bits_per_pixel;
-       unsigned long *dst;
-       int dst_idx, left;
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
-               fg = ((u32 *) (p->pseudo_palette))[rect->color];
-       else
-               fg = rect->color;
-
-       pat = pixel_to_pat( bpp, fg);
-
-       dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
-       dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
-       dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
-       /* FIXME For now we support 1-32 bpp only */
-       left = bits % bpp;
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-       if (!left) {
-               void (*fill_op32)(struct fb_info *p, unsigned long *dst,
-                                 int dst_idx, unsigned long pat, unsigned n,
-                                 int bits) = NULL;
-
-               switch (rect->rop) {
-               case ROP_XOR:
-                       fill_op32 = bitfill_aligned_rev;
-                       break;
-               case ROP_COPY:
-                       fill_op32 = bitfill_aligned;
-                       break;
-               default:
-                       printk( KERN_ERR "cfb_fillrect(): unknown rop, "
-                               "defaulting to ROP_COPY\n");
-                       fill_op32 = bitfill_aligned;
-                       break;
-               }
-               while (height--) {
-                       dst += dst_idx >> (ffs(bits) - 1);
-                       dst_idx &= (bits - 1);
-                       fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
-                       dst_idx += p->fix.line_length*8;
-               }
-       } else {
-               int right, r;
-               void (*fill_op)(struct fb_info *p, unsigned long *dst,
-                               int dst_idx, unsigned long pat, int left,
-                               int right, unsigned n, int bits) = NULL;
-#ifdef __LITTLE_ENDIAN
-               right = left;
-               left = bpp - right;
-#else
-               right = bpp - left;
-#endif
-               switch (rect->rop) {
-               case ROP_XOR:
-                       fill_op = bitfill_unaligned_rev;
-                       break;
-               case ROP_COPY:
-                       fill_op = bitfill_unaligned;
-                       break;
-               default:
-                       printk(KERN_ERR "sys_fillrect(): unknown rop, "
-                               "defaulting to ROP_COPY\n");
-                       fill_op = bitfill_unaligned;
-                       break;
-               }
-               while (height--) {
-                       dst += dst_idx / bits;
-                       dst_idx &= (bits - 1);
-                       r = dst_idx % bpp;
-                       /* rotate pattern to the correct start position */
-                       pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
-                       fill_op(p, dst, dst_idx, pat2, left, right,
-                               width*bpp, bits);
-                       dst_idx += p->fix.line_length*8;
-               }
-       }
-}
-
-EXPORT_SYMBOL(sys_fillrect);
-
-MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
-MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/sysimgblt.c b/drivers/video/fbdev/sysimgblt.c
deleted file mode 100644 (file)
index a4d05b1..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *  Generic 1-bit or 8-bit source to 1-32 bit destination expansion
- *  for frame buffer located in system RAM with packed pixels of any depth.
- *
- *  Based almost entirely on cfbimgblt.c
- *
- *      Copyright (C)  April 2007 Antonino Daplas <adaplas@pol.net>
- *
- *  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.
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fb.h>
-#include <asm/types.h>
-
-#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-static const u32 cfb_tab8_be[] = {
-    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
-    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
-    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
-    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
-};
-
-static const u32 cfb_tab8_le[] = {
-    0x00000000,0xff000000,0x00ff0000,0xffff0000,
-    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
-    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
-    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
-};
-
-static const u32 cfb_tab16_be[] = {
-    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
-};
-
-static const u32 cfb_tab16_le[] = {
-    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
-};
-
-static const u32 cfb_tab32[] = {
-       0x00000000, 0xffffffff
-};
-
-static void color_imageblit(const struct fb_image *image, struct fb_info *p,
-                           void *dst1, u32 start_index, u32 pitch_index)
-{
-       /* Draw the penguin */
-       u32 *dst, *dst2;
-       u32 color = 0, val, shift;
-       int i, n, bpp = p->var.bits_per_pixel;
-       u32 null_bits = 32 - bpp;
-       u32 *palette = (u32 *) p->pseudo_palette;
-       const u8 *src = image->data;
-
-       dst2 = dst1;
-       for (i = image->height; i--; ) {
-               n = image->width;
-               dst = dst1;
-               shift = 0;
-               val = 0;
-
-               if (start_index) {
-                       u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
-                                                        start_index));
-                       val = *dst & start_mask;
-                       shift = start_index;
-               }
-               while (n--) {
-                       if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-                           p->fix.visual == FB_VISUAL_DIRECTCOLOR )
-                               color = palette[*src];
-                       else
-                               color = *src;
-                       color <<= FB_LEFT_POS(p, bpp);
-                       val |= FB_SHIFT_HIGH(p, color, shift);
-                       if (shift >= null_bits) {
-                               *dst++ = val;
-
-                               val = (shift == null_bits) ? 0 :
-                                       FB_SHIFT_LOW(p, color, 32 - shift);
-                       }
-                       shift += bpp;
-                       shift &= (32 - 1);
-                       src++;
-               }
-               if (shift) {
-                       u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
-
-                       *dst &= end_mask;
-                       *dst |= val;
-               }
-               dst1 += p->fix.line_length;
-               if (pitch_index) {
-                       dst2 += p->fix.line_length;
-                       dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
-
-                       start_index += pitch_index;
-                       start_index &= 32 - 1;
-               }
-       }
-}
-
-static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
-                                 void *dst1, u32 fgcolor, u32 bgcolor,
-                                 u32 start_index, u32 pitch_index)
-{
-       u32 shift, color = 0, bpp = p->var.bits_per_pixel;
-       u32 *dst, *dst2;
-       u32 val, pitch = p->fix.line_length;
-       u32 null_bits = 32 - bpp;
-       u32 spitch = (image->width+7)/8;
-       const u8 *src = image->data, *s;
-       u32 i, j, l;
-
-       dst2 = dst1;
-       fgcolor <<= FB_LEFT_POS(p, bpp);
-       bgcolor <<= FB_LEFT_POS(p, bpp);
-
-       for (i = image->height; i--; ) {
-               shift = val = 0;
-               l = 8;
-               j = image->width;
-               dst = dst1;
-               s = src;
-
-               /* write leading bits */
-               if (start_index) {
-                       u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
-                                                        start_index));
-                       val = *dst & start_mask;
-                       shift = start_index;
-               }
-
-               while (j--) {
-                       l--;
-                       color = (*s & (1 << l)) ? fgcolor : bgcolor;
-                       val |= FB_SHIFT_HIGH(p, color, shift);
-
-                       /* Did the bitshift spill bits to the next long? */
-                       if (shift >= null_bits) {
-                               *dst++ = val;
-                               val = (shift == null_bits) ? 0 :
-                                       FB_SHIFT_LOW(p, color, 32 - shift);
-                       }
-                       shift += bpp;
-                       shift &= (32 - 1);
-                       if (!l) { l = 8; s++; }
-               }
-
-               /* write trailing bits */
-               if (shift) {
-                       u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
-
-                       *dst &= end_mask;
-                       *dst |= val;
-               }
-
-               dst1 += pitch;
-               src += spitch;
-               if (pitch_index) {
-                       dst2 += pitch;
-                       dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
-                       start_index += pitch_index;
-                       start_index &= 32 - 1;
-               }
-
-       }
-}
-
-/*
- * fast_imageblit - optimized monochrome color expansion
- *
- * Only if:  bits_per_pixel == 8, 16, or 32
- *           image->width is divisible by pixel/dword (ppw);
- *           fix->line_legth is divisible by 4;
- *           beginning and end of a scanline is dword aligned
- */
-static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
-                                 void *dst1, u32 fgcolor, u32 bgcolor)
-{
-       u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
-       u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
-       u32 bit_mask, end_mask, eorx, shift;
-       const char *s = image->data, *src;
-       u32 *dst;
-       const u32 *tab = NULL;
-       int i, j, k;
-
-       switch (bpp) {
-       case 8:
-               tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
-               break;
-       case 16:
-               tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
-               break;
-       case 32:
-       default:
-               tab = cfb_tab32;
-               break;
-       }
-
-       for (i = ppw-1; i--; ) {
-               fgx <<= bpp;
-               bgx <<= bpp;
-               fgx |= fgcolor;
-               bgx |= bgcolor;
-       }
-
-       bit_mask = (1 << ppw) - 1;
-       eorx = fgx ^ bgx;
-       k = image->width/ppw;
-
-       for (i = image->height; i--; ) {
-               dst = dst1;
-               shift = 8;
-               src = s;
-
-               for (j = k; j--; ) {
-                       shift -= ppw;
-                       end_mask = tab[(*src >> shift) & bit_mask];
-                       *dst++ = (end_mask & eorx) ^ bgx;
-                       if (!shift) {
-                               shift = 8;
-                               src++;
-                       }
-               }
-               dst1 += p->fix.line_length;
-               s += spitch;
-       }
-}
-
-void sys_imageblit(struct fb_info *p, const struct fb_image *image)
-{
-       u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
-       u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
-       u32 width = image->width;
-       u32 dx = image->dx, dy = image->dy;
-       void *dst1;
-
-       if (p->state != FBINFO_STATE_RUNNING)
-               return;
-
-       bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
-       start_index = bitstart & (32 - 1);
-       pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
-
-       bitstart /= 8;
-       bitstart &= ~(bpl - 1);
-       dst1 = (void __force *)p->screen_base + bitstart;
-
-       if (p->fbops->fb_sync)
-               p->fbops->fb_sync(p);
-
-       if (image->depth == 1) {
-               if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
-                   p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-                       fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
-                       bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
-               } else {
-                       fgcolor = image->fg_color;
-                       bgcolor = image->bg_color;
-               }
-
-               if (32 % bpp == 0 && !start_index && !pitch_index &&
-                   ((width & (32/bpp-1)) == 0) &&
-                   bpp >= 8 && bpp <= 32)
-                       fast_imageblit(image, p, dst1, fgcolor, bgcolor);
-               else
-                       slow_imageblit(image, p, dst1, fgcolor, bgcolor,
-                                       start_index, pitch_index);
-       } else
-               color_imageblit(image, p, dst1, start_index, pitch_index);
-}
-
-EXPORT_SYMBOL(sys_imageblit);
-
-MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
-MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
-MODULE_LICENSE("GPL");
-
index b0a9f34b2e01b7b45b1a0d86e25889e3f52fc434..9df6fe78a44b283c00929e0cf021dc1a3676be8e 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/module.h>
 #include <linux/fb.h>
 #include <linux/platform_device.h>
-#include "fb_draw.h"
+#include "core/fb_draw.h"
 
 #define GE_COMMAND_OFF         0x00
 #define GE_DEPTH_OFF           0x04