Merge to kernel-2.6.20-1.2949.fc6.vs2.2.0.1
[linux-2.6.git] / drivers / video / sis / sis_accel.c
index 07e29d7..7addf91 100644 (file)
@@ -1,6 +1,8 @@
 /*
- * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver
- * for Linux kernels 2.4.x and 2.6.x
+ * SiS 300/540/630[S]/730[S],
+ * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
+ * XGI V3XT/V5/V8, Z7
+ * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
  *
  * 2D acceleration part
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * Based on the XFree86 driver's sis300_accel.c which is
- *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
- * and sis310_accel.c which is
- *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
+ * Based on the XFree86/X.org driver which is
+ *     Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
  *
  * Author: Thomas Winischhofer <thomas@winischhofer.net>
  *                     (see http://www.winischhofer.net/
  *                     for more information and updates)
  */
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
 #include <linux/fb.h>
-#include <linux/console.h>
-#include <linux/selection.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vt_kern.h>
-#include <linux/capability.h>
-#include <linux/fs.h>
-#include <linux/agp_backend.h>
-
 #include <linux/types.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/sisfb.h>
-#else
-#include <video/sisfb.h>
-#endif
-
 #include <asm/io.h>
 
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#endif
-
-#include "osdef.h"
-#include "vgatypes.h"
-#include "vstruct.h"
-#include "sis_accel.h"
 #include "sis.h"
+#include "sis_accel.h"
 
-extern struct     video_info ivideo;
-extern VGA_ENGINE sisvga_engine;
-extern int sisfb_accel;
-
-static const int sisALUConv[] =
+static const u8 sisALUConv[] =
 {
     0x00,       /* dest = 0;            0,      GXclear,        0 */
     0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
@@ -101,7 +59,7 @@ static const int sisALUConv[] =
     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
 };
 /* same ROP but with Pattern as Source */
-static const int sisPatALUConv[] =
+static const u8 sisPatALUConv[] =
 {
     0x00,       /* dest = 0;            0,      GXclear,        0 */
     0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
@@ -121,27 +79,25 @@ static const int sisPatALUConv[] =
     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
 };
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
-static const unsigned char myrops[] = {
+static const int myrops[] = {
        3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
-   };
-#endif
+};
 
 /* 300 series ----------------------------------------------------- */
 #ifdef CONFIG_FB_SIS_300
 static void
-SiS300Sync(void)
+SiS300Sync(struct sis_video_info *ivideo)
 {
        SiS300Idle
 }
 
 static void
-SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
-                                unsigned int planemask, int trans_color)
+SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
+                                 int rop, int trans_color)
 {
-       SiS300SetupDSTColorDepth(ivideo.DstColor);
-       SiS300SetupSRCPitch(ivideo.video_linelength)
-       SiS300SetupDSTRect(ivideo.video_linelength, -1)
+       SiS300SetupDSTColorDepth(ivideo->DstColor);
+       SiS300SetupSRCPitch(ivideo->video_linelength)
+       SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
 
        if(trans_color != -1) {
                SiS300SetupROP(0x0A)
@@ -159,29 +115,28 @@ SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
 }
 
 static void
-SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
-                                int width, int height)
+SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
+                                  int src_y, int dst_x, int dst_y, int width, int height)
 {
-       long srcbase, dstbase;
+       u32 srcbase = 0, dstbase = 0;
 
-       srcbase = dstbase = 0;
-       if (src_y >= 2048) {
-               srcbase = ivideo.video_linelength * src_y;
+       if(src_y >= 2048) {
+               srcbase = ivideo->video_linelength * src_y;
                src_y = 0;
        }
-       if (dst_y >= 2048) {
-               dstbase = ivideo.video_linelength * dst_y;
+       if(dst_y >= 2048) {
+               dstbase = ivideo->video_linelength * dst_y;
                dst_y = 0;
        }
 
        SiS300SetupSRCBase(srcbase);
        SiS300SetupDSTBase(dstbase);
 
-       if(!(ivideo.CommandReg & X_INC))  {
+       if(!(ivideo->CommandReg & X_INC))  {
                src_x += width-1;
                dst_x += width-1;
        }
-       if(!(ivideo.CommandReg & Y_INC))  {
+       if(!(ivideo->CommandReg & Y_INC))  {
                src_y += height-1;
                dst_y += height-1;
        }
@@ -192,23 +147,22 @@ SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
 }
 
 static void
-SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
+SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 {
        SiS300SetupPATFG(color)
-       SiS300SetupDSTRect(ivideo.video_linelength, -1)
-       SiS300SetupDSTColorDepth(ivideo.DstColor);
+       SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
+       SiS300SetupDSTColorDepth(ivideo->DstColor);
        SiS300SetupROP(sisPatALUConv[rop])
        SiS300SetupCMDFlag(PATFG)
 }
 
 static void
-SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
+SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 {
-       long dstbase;
+       u32 dstbase = 0;
 
-       dstbase = 0;
        if(y >= 2048) {
-               dstbase = ivideo.video_linelength * y;
+               dstbase = ivideo->video_linelength * y;
                y = 0;
        }
        SiS300SetupDSTBase(dstbase)
@@ -219,23 +173,22 @@ SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
 }
 #endif
 
-/* 315/330 series ------------------------------------------------- */
+/* 315/330/340 series ---------------------------------------------- */
 
 #ifdef CONFIG_FB_SIS_315
 static void
-SiS310Sync(void)
+SiS310Sync(struct sis_video_info *ivideo)
 {
        SiS310Idle
 }
 
 static void
-SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
-                                unsigned int planemask, int trans_color)
+SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
 {
-       SiS310SetupDSTColorDepth(ivideo.DstColor);
-       SiS310SetupSRCPitch(ivideo.video_linelength)
-       SiS310SetupDSTRect(ivideo.video_linelength, -1)
-       if (trans_color != -1) {
+       SiS310SetupDSTColorDepth(ivideo->DstColor);
+       SiS310SetupSRCPitch(ivideo->video_linelength)
+       SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
+       if(trans_color != -1) {
                SiS310SetupROP(0x0A)
                SiS310SetupSRCTrans(trans_color)
                SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
@@ -244,49 +197,49 @@ SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
                /* Set command - not needed, both 0 */
                /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
        }
-       SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
-       /* The 315 series is smart enough to know the direction */
+       SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
+       /* The chip is smart enough to know the direction */
 }
 
 static void
-SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
-                                int width, int height)
+SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
+                        int dst_x, int dst_y, int width, int height)
 {
-       long srcbase, dstbase;
-       int mymin, mymax;
+       u32 srcbase = 0, dstbase = 0;
+       int mymin = min(src_y, dst_y);
+       int mymax = max(src_y, dst_y);
 
-       srcbase = dstbase = 0;
-       mymin = min(src_y, dst_y);
-       mymax = max(src_y, dst_y);
-       
        /* Although the chip knows the direction to use
-        * if the source and destination areas overlap, 
+        * if the source and destination areas overlap,
         * that logic fails if we fiddle with the bitmap
         * addresses. Therefore, we check if the source
-        * and destination blitting areas overlap and 
-        * adapt the bitmap addresses synchronously 
+        * and destination blitting areas overlap and
+        * adapt the bitmap addresses synchronously
         * if the coordinates exceed the valid range.
-        * The the areas do not overlap, we do our 
+        * The the areas do not overlap, we do our
         * normal check.
         */
-       if((mymax - mymin) < height) { 
-          if((src_y >= 2048) || (dst_y >= 2048)) {           
-             srcbase = ivideo.video_linelength * mymin;
-             dstbase = ivideo.video_linelength * mymin;
-             src_y -= mymin;
-             dst_y -= mymin;
-          }
+       if((mymax - mymin) < height) {
+               if((src_y >= 2048) || (dst_y >= 2048)) {
+                       srcbase = ivideo->video_linelength * mymin;
+                       dstbase = ivideo->video_linelength * mymin;
+                       src_y -= mymin;
+                       dst_y -= mymin;
+               }
        } else {
-          if(src_y >= 2048) {
-             srcbase = ivideo.video_linelength * src_y;
-             src_y = 0;
-          }
-          if(dst_y >= 2048) {
-             dstbase = ivideo.video_linelength * dst_y;
-             dst_y = 0;
-          }
+               if(src_y >= 2048) {
+                       srcbase = ivideo->video_linelength * src_y;
+                       src_y = 0;
+               }
+               if(dst_y >= 2048) {
+                       dstbase = ivideo->video_linelength * dst_y;
+                       dst_y = 0;
+               }
        }
 
+       srcbase += ivideo->video_offset;
+       dstbase += ivideo->video_offset;
+
        SiS310SetupSRCBase(srcbase);
        SiS310SetupDSTBase(dstbase);
        SiS310SetupRect(width, height)
@@ -296,25 +249,25 @@ SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
 }
 
 static void
-SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
+SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 {
        SiS310SetupPATFG(color)
-       SiS310SetupDSTRect(ivideo.video_linelength, -1)
-       SiS310SetupDSTColorDepth(ivideo.DstColor);
+       SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
+       SiS310SetupDSTColorDepth(ivideo->DstColor);
        SiS310SetupROP(sisPatALUConv[rop])
-       SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
+       SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
 }
 
 static void
-SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
+SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 {
-       long dstbase;
+       u32 dstbase = 0;
 
-       dstbase = 0;
        if(y >= 2048) {
-               dstbase = ivideo.video_linelength * y;
+               dstbase = ivideo->video_linelength * y;
                y = 0;
        }
+       dstbase += ivideo->video_offset;
        SiS310SetupDSTBase(dstbase)
        SiS310SetupDSTXY(x,y)
        SiS310SetupRect(w,h)
@@ -327,351 +280,145 @@ SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
 
 /* The exported routines */
 
-int sisfb_initaccel(void)
+int sisfb_initaccel(struct sis_video_info *ivideo)
 {
 #ifdef SISFB_USE_SPINLOCKS
-    spin_lock_init(&ivideo.lockaccel);
+       spin_lock_init(&ivideo->lockaccel);
 #endif
-    return(0);
+       return 0;
 }
 
-void sisfb_syncaccel(void)
+void sisfb_syncaccel(struct sis_video_info *ivideo)
 {
-    if(sisvga_engine == SIS_300_VGA) {
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
-       SiS300Sync();
+               SiS300Sync(ivideo);
 #endif
-    } else {
+       } else {
 #ifdef CONFIG_FB_SIS_315
-       SiS310Sync();
+               SiS310Sync(ivideo);
 #endif
-    }
+       }
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  /* --------------- 2.5 --------------- */
-
 int fbcon_sis_sync(struct fb_info *info)
 {
-   CRITFLAGS
-
-   if(!ivideo.accel)
-       return 0;
-
-   if(sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-      SiS300Sync();
-#endif
-   } else {
-#ifdef CONFIG_FB_SIS_315
-      SiS310Sync();
-#endif
-   }
-   CRITEND
-   return 0;
-}
-
-void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
-   int col=0;
-   CRITFLAGS
-
-   TWDEBUG("Inside sis_fillrect");
-   if(!rect->width || !rect->height)
-       return;
-
-   if(!ivideo.accel) {
-       cfb_fillrect(info, rect);
-       return;
-   }
-   
-   switch(info->var.bits_per_pixel) {
-       case 8:  col = rect->color;
-                break;
-       case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
-                break;
-       case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
-                break;
-   }
-
-   if(sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-      CRITBEGIN
-      SiS300SetupForSolidFill(col, myrops[rect->rop], 0);
-      SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
-      CRITEND
-      SiS300Sync();
-#endif
-   } else {
-#ifdef CONFIG_FB_SIS_315
-      CRITBEGIN
-      SiS310SetupForSolidFill(col, myrops[rect->rop], 0);
-      SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
-      CRITEND
-      SiS310Sync();
-#endif
-   }
-
-}
-
-void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
-{
-   int xdir, ydir;
-   CRITFLAGS
-
-   TWDEBUG("Inside sis_copyarea");
-   if(!ivideo.accel) {
-       cfb_copyarea(info, area);
-       return;
-   }
+       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+       CRITFLAGS
 
-   if(!area->width || !area->height)
-       return;
+       if((!ivideo->accel) || (!ivideo->engineok))
+               return 0;
 
-   if(area->sx < area->dx) xdir = 0;
-   else                    xdir = 1;
-   if(area->sy < area->dy) ydir = 0;
-   else                    ydir = 1;
+       CRITBEGIN
+       sisfb_syncaccel(ivideo);
+       CRITEND
 
-   if(sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-      CRITBEGIN
-      SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-      SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
-      CRITEND
-      SiS300Sync();
-#endif
-   } else {
-#ifdef CONFIG_FB_SIS_315
-      CRITBEGIN
-      SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-      SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
-      CRITEND
-      SiS310Sync();
-#endif
-   }
+       return 0;
 }
 
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  /* -------------- 2.4 --------------- */
-
-void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
-                           int dsty, int dstx, int height, int width)
+void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-        int xdir, ydir;
+       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+       u32 col = 0;
+       u32 vxres = info->var.xres_virtual;
+       u32 vyres = info->var.yres_virtual;
+       int width, height;
        CRITFLAGS
 
-       if(!ivideo.accel) {
-           switch(ivideo.video_bpp) {
-           case 8:
-#ifdef FBCON_HAS_CFB8
-              fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
-              break;
-           case 16:
-#ifdef FBCON_HAS_CFB16
-              fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
-              break;
-           case 32:
-#ifdef FBCON_HAS_CFB32
-              fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
-              break;
-            }
-           return;
+       if(info->state != FBINFO_STATE_RUNNING)
+               return;
+
+       if((!ivideo->accel) || (!ivideo->engineok)) {
+               cfb_fillrect(info, rect);
+               return;
        }
 
-       srcx *= fontwidth(p);
-       srcy *= fontheight(p);
-       dstx *= fontwidth(p);
-       dsty *= fontheight(p);
-       width *= fontwidth(p);
-       height *= fontheight(p);
+       if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres)
+               return;
 
-       if(srcx < dstx) xdir = 0;
-       else            xdir = 1;
-       if(srcy < dsty) ydir = 0;
-       else            ydir = 1;
+       /* Clipping */
+       width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
+       height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
 
-       if(sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-          CRITBEGIN
-          SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-          SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
-          CRITEND
-          SiS300Sync();
-#endif
-       } else {
-#ifdef CONFIG_FB_SIS_315
-          CRITBEGIN
-          SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-          SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
-          CRITEND
-          SiS310Sync();
-#if 0
-          printk(KERN_INFO "sis_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
-               srcx, srcy, dstx, dsty, width, height);
-#endif
-#endif
+       switch(info->var.bits_per_pixel) {
+       case 8:  col = rect->color;
+                break;
+       case 16:
+       case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
+                break;
        }
-}
 
-static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
-                       int srcy, int srcx, int height, int width, int color)
-{
-       CRITFLAGS
-
-       srcx *= fontwidth(p);
-       srcy *= fontheight(p);
-       width *= fontwidth(p);
-       height *= fontheight(p);
-
-       if(sisvga_engine == SIS_300_VGA) {
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
-          CRITBEGIN
-          SiS300SetupForSolidFill(color, 3, 0);
-          SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
-          CRITEND
-          SiS300Sync();
+               CRITBEGIN
+               SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+               SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
+               CRITEND
 #endif
        } else {
 #ifdef CONFIG_FB_SIS_315
-          CRITBEGIN
-          SiS310SetupForSolidFill(color, 3, 0);
-          SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
-          CRITEND
-          SiS310Sync();
+               CRITBEGIN
+               SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+               SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
+               CRITEND
 #endif
        }
-}
 
-void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
-                       int srcy, int srcx, int height, int width)
-{
-       u32 bgx;
-
-       if(!ivideo.accel) {
-#ifdef FBCON_HAS_CFB8
-           fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
-#endif
-           return;
-       }
-
-       bgx = attr_bgcol_ec(p, conp);
-       fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+       sisfb_syncaccel(ivideo);
 }
 
-void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
-                       int srcy, int srcx, int height, int width)
+void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
-       u32 bgx;
-       if(!ivideo.accel) {
-#ifdef FBCON_HAS_CFB16
-           fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
-#endif
-           return;
-       }
-
-       bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
-       fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
-}
+       struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+       u32 vxres = info->var.xres_virtual;
+       u32 vyres = info->var.yres_virtual;
+       int width = area->width;
+       int height = area->height;
+       CRITFLAGS
 
-void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
-                       int srcy, int srcx, int height, int width)
-{
-       u32 bgx;
+       if(info->state != FBINFO_STATE_RUNNING)
+               return;
 
-       if(!ivideo.accel) {
-#ifdef FBCON_HAS_CFB32
-           fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
-#endif
-           return;
+       if((!ivideo->accel) || (!ivideo->engineok)) {
+               cfb_copyarea(info, area);
+               return;
        }
 
-       bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
-       fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
-}
+       if(!width || !height ||
+          area->sx >= vxres || area->sy >= vyres ||
+          area->dx >= vxres || area->dy >= vyres)
+               return;
 
-void fbcon_sis_revc(struct display *p, int srcx, int srcy)
-{
-       CRITFLAGS
+       /* Clipping */
+       if((area->sx + width) > vxres) width = vxres - area->sx;
+       if((area->dx + width) > vxres) width = vxres - area->dx;
+       if((area->sy + height) > vyres) height = vyres - area->sy;
+       if((area->dy + height) > vyres) height = vyres - area->dy;
 
-       if(!ivideo.accel) {
-           switch(ivideo.video_bpp) {
-           case 16:
-#ifdef FBCON_HAS_CFB16
-              fbcon_cfb16_revc(p, srcx, srcy);
-#endif
-              break;
-           case 32:
-#ifdef FBCON_HAS_CFB32
-              fbcon_cfb32_revc(p, srcx, srcy);
-#endif
-              break;
-            }
-           return;
-       }
+       if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+               int xdir, ydir;
 
-       srcx *= fontwidth(p);
-       srcy *= fontheight(p);
+               if(area->sx < area->dx) xdir = 0;
+               else                    xdir = 1;
+               if(area->sy < area->dy) ydir = 0;
+               else                    ydir = 1;
 
-       if(sisvga_engine == SIS_300_VGA) {
-#ifdef CONFIG_FB_SIS_300
-          CRITBEGIN
-          SiS300SetupForSolidFill(0, 0x0a, 0);
-          SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
-          CRITEND
-          SiS300Sync();
+               CRITBEGIN
+               SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
+               SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
+                                       area->dx, area->dy, width, height);
+               CRITEND
 #endif
        } else {
 #ifdef CONFIG_FB_SIS_315
-          CRITBEGIN
-          SiS310SetupForSolidFill(0, 0x0a, 0);
-          SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
-          CRITEND
-          SiS310Sync();
+               CRITBEGIN
+               SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
+               SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
+                                       area->dx, area->dy, width, height);
+               CRITEND
 #endif
        }
-}
-
-#ifdef FBCON_HAS_CFB8
-struct display_switch fbcon_sis8 = {
-       .setup                  = fbcon_cfb8_setup,
-       .bmove                  = fbcon_sis_bmove,
-       .clear                  = fbcon_sis_clear8,
-       .putc                   = fbcon_cfb8_putc,
-       .putcs                  = fbcon_cfb8_putcs,
-       .revc                   = fbcon_cfb8_revc,
-       .clear_margins          = fbcon_cfb8_clear_margins,
-       .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-#ifdef FBCON_HAS_CFB16
-struct display_switch fbcon_sis16 = {
-       .setup                  = fbcon_cfb16_setup,
-       .bmove                  = fbcon_sis_bmove,
-       .clear                  = fbcon_sis_clear16,
-       .putc                   = fbcon_cfb16_putc,
-       .putcs                  = fbcon_cfb16_putcs,
-       .revc                   = fbcon_sis_revc,
-       .clear_margins          = fbcon_cfb16_clear_margins,
-       .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-#ifdef FBCON_HAS_CFB32
-struct display_switch fbcon_sis32 = {
-       .setup                  = fbcon_cfb32_setup,
-       .bmove                  = fbcon_sis_bmove,
-       .clear                  = fbcon_sis_clear32,
-       .putc                   = fbcon_cfb32_putc,
-       .putcs                  = fbcon_cfb32_putcs,
-       .revc                   = fbcon_sis_revc,
-       .clear_margins          = fbcon_cfb32_clear_margins,
-       .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#endif /* KERNEL VERSION */
-
 
+       sisfb_syncaccel(ivideo);
+}