ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / video / sis / sis_accel.c
1 /*
2  * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver
3  * for Linux kernels 2.4.x and 2.6.x
4  *
5  * 2D acceleration part
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the named License,
10  * or any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20  *
21  * Based on the XFree86 driver's sis300_accel.c which is
22  *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
23  * and sis310_accel.c which is
24  *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
25  *
26  * Author: Thomas Winischhofer <thomas@winischhofer.net>
27  *                      (see http://www.winischhofer.net/
28  *                      for more information and updates)
29  */
30
31 #include <linux/config.h>
32 #include <linux/version.h>
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/errno.h>
36 #include <linux/string.h>
37 #include <linux/mm.h>
38 #include <linux/tty.h>
39 #include <linux/slab.h>
40 #include <linux/delay.h>
41 #include <linux/fb.h>
42 #include <linux/console.h>
43 #include <linux/selection.h>
44 #include <linux/ioport.h>
45 #include <linux/init.h>
46 #include <linux/pci.h>
47 #include <linux/vt_kern.h>
48 #include <linux/capability.h>
49 #include <linux/fs.h>
50 #include <linux/agp_backend.h>
51
52 #include <linux/types.h>
53
54 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
55 #include <linux/sisfb.h>
56 #else
57 #include <video/sisfb.h>
58 #endif
59
60 #include <asm/io.h>
61
62 #ifdef CONFIG_MTRR
63 #include <asm/mtrr.h>
64 #endif
65
66 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
67 #include <video/fbcon.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
72 #endif
73
74 #include "osdef.h"
75 #include "vgatypes.h"
76 #include "vstruct.h"
77 #include "sis_accel.h"
78 #include "sis.h"
79
80 extern struct     video_info ivideo;
81 extern VGA_ENGINE sisvga_engine;
82 extern int sisfb_accel;
83
84 static const int sisALUConv[] =
85 {
86     0x00,       /* dest = 0;            0,      GXclear,        0 */
87     0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
88     0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
89     0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
90     0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
91     0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
92     0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
93     0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
94     0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
95     0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
96     0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
97     0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
98     0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
99     0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
100     0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
101     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
102 };
103 /* same ROP but with Pattern as Source */
104 static const int sisPatALUConv[] =
105 {
106     0x00,       /* dest = 0;            0,      GXclear,        0 */
107     0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
108     0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
109     0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
110     0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
111     0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
112     0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
113     0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
114     0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
115     0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
116     0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
117     0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
118     0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
119     0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
120     0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
121     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
122 };
123
124 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
125 static const unsigned char myrops[] = {
126         3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
127    };
128 #endif
129
130 /* 300 series ----------------------------------------------------- */
131 #ifdef CONFIG_FB_SIS_300
132 static void
133 SiS300Sync(void)
134 {
135         SiS300Idle
136 }
137
138 static void
139 SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
140                                 unsigned int planemask, int trans_color)
141 {
142         SiS300SetupDSTColorDepth(ivideo.DstColor);
143         SiS300SetupSRCPitch(ivideo.video_linelength)
144         SiS300SetupDSTRect(ivideo.video_linelength, -1)
145
146         if(trans_color != -1) {
147                 SiS300SetupROP(0x0A)
148                 SiS300SetupSRCTrans(trans_color)
149                 SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
150         } else {
151                 SiS300SetupROP(sisALUConv[rop])
152         }
153         if(xdir > 0) {
154                 SiS300SetupCMDFlag(X_INC)
155         }
156         if(ydir > 0) {
157                 SiS300SetupCMDFlag(Y_INC)
158         }
159 }
160
161 static void
162 SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
163                                 int width, int height)
164 {
165         long srcbase, dstbase;
166
167         srcbase = dstbase = 0;
168         if (src_y >= 2048) {
169                 srcbase = ivideo.video_linelength * src_y;
170                 src_y = 0;
171         }
172         if (dst_y >= 2048) {
173                 dstbase = ivideo.video_linelength * dst_y;
174                 dst_y = 0;
175         }
176
177         SiS300SetupSRCBase(srcbase);
178         SiS300SetupDSTBase(dstbase);
179
180         if(!(ivideo.CommandReg & X_INC))  {
181                 src_x += width-1;
182                 dst_x += width-1;
183         }
184         if(!(ivideo.CommandReg & Y_INC))  {
185                 src_y += height-1;
186                 dst_y += height-1;
187         }
188         SiS300SetupRect(width, height)
189         SiS300SetupSRCXY(src_x, src_y)
190         SiS300SetupDSTXY(dst_x, dst_y)
191         SiS300DoCMD
192 }
193
194 static void
195 SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
196 {
197         SiS300SetupPATFG(color)
198         SiS300SetupDSTRect(ivideo.video_linelength, -1)
199         SiS300SetupDSTColorDepth(ivideo.DstColor);
200         SiS300SetupROP(sisPatALUConv[rop])
201         SiS300SetupCMDFlag(PATFG)
202 }
203
204 static void
205 SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
206 {
207         long dstbase;
208
209         dstbase = 0;
210         if(y >= 2048) {
211                 dstbase = ivideo.video_linelength * y;
212                 y = 0;
213         }
214         SiS300SetupDSTBase(dstbase)
215         SiS300SetupDSTXY(x,y)
216         SiS300SetupRect(w,h)
217         SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
218         SiS300DoCMD
219 }
220 #endif
221
222 /* 315/330 series ------------------------------------------------- */
223
224 #ifdef CONFIG_FB_SIS_315
225 static void
226 SiS310Sync(void)
227 {
228         SiS310Idle
229 }
230
231 static void
232 SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
233                                 unsigned int planemask, int trans_color)
234 {
235         SiS310SetupDSTColorDepth(ivideo.DstColor);
236         SiS310SetupSRCPitch(ivideo.video_linelength)
237         SiS310SetupDSTRect(ivideo.video_linelength, -1)
238         if (trans_color != -1) {
239                 SiS310SetupROP(0x0A)
240                 SiS310SetupSRCTrans(trans_color)
241                 SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
242         } else {
243                 SiS310SetupROP(sisALUConv[rop])
244                 /* Set command - not needed, both 0 */
245                 /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
246         }
247         SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
248         /* The 315 series is smart enough to know the direction */
249 }
250
251 static void
252 SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
253                                 int width, int height)
254 {
255         long srcbase, dstbase;
256         int mymin, mymax;
257
258         srcbase = dstbase = 0;
259         mymin = min(src_y, dst_y);
260         mymax = max(src_y, dst_y);
261         
262         /* Although the chip knows the direction to use
263          * if the source and destination areas overlap, 
264          * that logic fails if we fiddle with the bitmap
265          * addresses. Therefore, we check if the source
266          * and destination blitting areas overlap and 
267          * adapt the bitmap addresses synchronously 
268          * if the coordinates exceed the valid range.
269          * The the areas do not overlap, we do our 
270          * normal check.
271          */
272         if((mymax - mymin) < height) { 
273            if((src_y >= 2048) || (dst_y >= 2048)) {           
274               srcbase = ivideo.video_linelength * mymin;
275               dstbase = ivideo.video_linelength * mymin;
276               src_y -= mymin;
277               dst_y -= mymin;
278            }
279         } else {
280            if(src_y >= 2048) {
281               srcbase = ivideo.video_linelength * src_y;
282               src_y = 0;
283            }
284            if(dst_y >= 2048) {
285               dstbase = ivideo.video_linelength * dst_y;
286               dst_y = 0;
287            }
288         }
289
290         SiS310SetupSRCBase(srcbase);
291         SiS310SetupDSTBase(dstbase);
292         SiS310SetupRect(width, height)
293         SiS310SetupSRCXY(src_x, src_y)
294         SiS310SetupDSTXY(dst_x, dst_y)
295         SiS310DoCMD
296 }
297
298 static void
299 SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
300 {
301         SiS310SetupPATFG(color)
302         SiS310SetupDSTRect(ivideo.video_linelength, -1)
303         SiS310SetupDSTColorDepth(ivideo.DstColor);
304         SiS310SetupROP(sisPatALUConv[rop])
305         SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
306 }
307
308 static void
309 SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
310 {
311         long dstbase;
312
313         dstbase = 0;
314         if(y >= 2048) {
315                 dstbase = ivideo.video_linelength * y;
316                 y = 0;
317         }
318         SiS310SetupDSTBase(dstbase)
319         SiS310SetupDSTXY(x,y)
320         SiS310SetupRect(w,h)
321         SiS310SetupCMDFlag(BITBLT)
322         SiS310DoCMD
323 }
324 #endif
325
326 /* --------------------------------------------------------------------- */
327
328 /* The exported routines */
329
330 int sisfb_initaccel(void)
331 {
332 #ifdef SISFB_USE_SPINLOCKS
333     spin_lock_init(&ivideo.lockaccel);
334 #endif
335     return(0);
336 }
337
338 void sisfb_syncaccel(void)
339 {
340     if(sisvga_engine == SIS_300_VGA) {
341 #ifdef CONFIG_FB_SIS_300
342         SiS300Sync();
343 #endif
344     } else {
345 #ifdef CONFIG_FB_SIS_315
346         SiS310Sync();
347 #endif
348     }
349 }
350
351 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  /* --------------- 2.5 --------------- */
352
353 int fbcon_sis_sync(struct fb_info *info)
354 {
355    CRITFLAGS
356
357    if(!ivideo.accel)
358         return 0;
359
360    if(sisvga_engine == SIS_300_VGA) {
361 #ifdef CONFIG_FB_SIS_300
362       SiS300Sync();
363 #endif
364    } else {
365 #ifdef CONFIG_FB_SIS_315
366       SiS310Sync();
367 #endif
368    }
369    CRITEND
370    return 0;
371 }
372
373 void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
374 {
375    int col=0;
376    CRITFLAGS
377
378    TWDEBUG("Inside sis_fillrect");
379    if(!rect->width || !rect->height)
380         return;
381
382    if(!ivideo.accel) {
383         cfb_fillrect(info, rect);
384         return;
385    }
386    
387    switch(info->var.bits_per_pixel) {
388         case 8:  col = rect->color;
389                  break;
390         case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
391                  break;
392         case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
393                  break;
394    }
395
396    if(sisvga_engine == SIS_300_VGA) {
397 #ifdef CONFIG_FB_SIS_300
398       CRITBEGIN
399       SiS300SetupForSolidFill(col, myrops[rect->rop], 0);
400       SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
401       CRITEND
402       SiS300Sync();
403 #endif
404    } else {
405 #ifdef CONFIG_FB_SIS_315
406       CRITBEGIN
407       SiS310SetupForSolidFill(col, myrops[rect->rop], 0);
408       SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
409       CRITEND
410       SiS310Sync();
411 #endif
412    }
413
414 }
415
416 void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
417 {
418    int xdir, ydir;
419    CRITFLAGS
420
421    TWDEBUG("Inside sis_copyarea");
422    if(!ivideo.accel) {
423         cfb_copyarea(info, area);
424         return;
425    }
426
427    if(!area->width || !area->height)
428         return;
429
430    if(area->sx < area->dx) xdir = 0;
431    else                    xdir = 1;
432    if(area->sy < area->dy) ydir = 0;
433    else                    ydir = 1;
434
435    if(sisvga_engine == SIS_300_VGA) {
436 #ifdef CONFIG_FB_SIS_300
437       CRITBEGIN
438       SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
439       SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
440       CRITEND
441       SiS300Sync();
442 #endif
443    } else {
444 #ifdef CONFIG_FB_SIS_315
445       CRITBEGIN
446       SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
447       SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
448       CRITEND
449       SiS310Sync();
450 #endif
451    }
452 }
453
454 #endif
455
456 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  /* -------------- 2.4 --------------- */
457
458 void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
459                             int dsty, int dstx, int height, int width)
460 {
461         int xdir, ydir;
462         CRITFLAGS
463
464         if(!ivideo.accel) {
465             switch(ivideo.video_bpp) {
466             case 8:
467 #ifdef FBCON_HAS_CFB8
468                fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
469 #endif
470                break;
471             case 16:
472 #ifdef FBCON_HAS_CFB16
473                fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
474 #endif
475                break;
476             case 32:
477 #ifdef FBCON_HAS_CFB32
478                fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
479 #endif
480                break;
481             }
482             return;
483         }
484
485         srcx *= fontwidth(p);
486         srcy *= fontheight(p);
487         dstx *= fontwidth(p);
488         dsty *= fontheight(p);
489         width *= fontwidth(p);
490         height *= fontheight(p);
491
492         if(srcx < dstx) xdir = 0;
493         else            xdir = 1;
494         if(srcy < dsty) ydir = 0;
495         else            ydir = 1;
496
497         if(sisvga_engine == SIS_300_VGA) {
498 #ifdef CONFIG_FB_SIS_300
499            CRITBEGIN
500            SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
501            SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
502            CRITEND
503            SiS300Sync();
504 #endif
505         } else {
506 #ifdef CONFIG_FB_SIS_315
507            CRITBEGIN
508            SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
509            SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
510            CRITEND
511            SiS310Sync();
512 #if 0
513            printk(KERN_INFO "sis_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
514                 srcx, srcy, dstx, dsty, width, height);
515 #endif
516 #endif
517         }
518 }
519
520 static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
521                         int srcy, int srcx, int height, int width, int color)
522 {
523         CRITFLAGS
524
525         srcx *= fontwidth(p);
526         srcy *= fontheight(p);
527         width *= fontwidth(p);
528         height *= fontheight(p);
529
530         if(sisvga_engine == SIS_300_VGA) {
531 #ifdef CONFIG_FB_SIS_300
532            CRITBEGIN
533            SiS300SetupForSolidFill(color, 3, 0);
534            SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
535            CRITEND
536            SiS300Sync();
537 #endif
538         } else {
539 #ifdef CONFIG_FB_SIS_315
540            CRITBEGIN
541            SiS310SetupForSolidFill(color, 3, 0);
542            SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
543            CRITEND
544            SiS310Sync();
545 #endif
546         }
547 }
548
549 void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
550                         int srcy, int srcx, int height, int width)
551 {
552         u32 bgx;
553
554         if(!ivideo.accel) {
555 #ifdef FBCON_HAS_CFB8
556             fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
557 #endif
558             return;
559         }
560
561         bgx = attr_bgcol_ec(p, conp);
562         fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
563 }
564
565 void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
566                         int srcy, int srcx, int height, int width)
567 {
568         u32 bgx;
569         if(!ivideo.accel) {
570 #ifdef FBCON_HAS_CFB16
571             fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
572 #endif
573             return;
574         }
575
576         bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
577         fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
578 }
579
580 void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
581                         int srcy, int srcx, int height, int width)
582 {
583         u32 bgx;
584
585         if(!ivideo.accel) {
586 #ifdef FBCON_HAS_CFB32
587             fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
588 #endif
589             return;
590         }
591
592         bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
593         fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
594 }
595
596 void fbcon_sis_revc(struct display *p, int srcx, int srcy)
597 {
598         CRITFLAGS
599
600         if(!ivideo.accel) {
601             switch(ivideo.video_bpp) {
602             case 16:
603 #ifdef FBCON_HAS_CFB16
604                fbcon_cfb16_revc(p, srcx, srcy);
605 #endif
606                break;
607             case 32:
608 #ifdef FBCON_HAS_CFB32
609                fbcon_cfb32_revc(p, srcx, srcy);
610 #endif
611                break;
612             }
613             return;
614         }
615
616         srcx *= fontwidth(p);
617         srcy *= fontheight(p);
618
619         if(sisvga_engine == SIS_300_VGA) {
620 #ifdef CONFIG_FB_SIS_300
621            CRITBEGIN
622            SiS300SetupForSolidFill(0, 0x0a, 0);
623            SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
624            CRITEND
625            SiS300Sync();
626 #endif
627         } else {
628 #ifdef CONFIG_FB_SIS_315
629            CRITBEGIN
630            SiS310SetupForSolidFill(0, 0x0a, 0);
631            SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
632            CRITEND
633            SiS310Sync();
634 #endif
635         }
636 }
637
638 #ifdef FBCON_HAS_CFB8
639 struct display_switch fbcon_sis8 = {
640         .setup                  = fbcon_cfb8_setup,
641         .bmove                  = fbcon_sis_bmove,
642         .clear                  = fbcon_sis_clear8,
643         .putc                   = fbcon_cfb8_putc,
644         .putcs                  = fbcon_cfb8_putcs,
645         .revc                   = fbcon_cfb8_revc,
646         .clear_margins          = fbcon_cfb8_clear_margins,
647         .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
648 };
649 #endif
650 #ifdef FBCON_HAS_CFB16
651 struct display_switch fbcon_sis16 = {
652         .setup                  = fbcon_cfb16_setup,
653         .bmove                  = fbcon_sis_bmove,
654         .clear                  = fbcon_sis_clear16,
655         .putc                   = fbcon_cfb16_putc,
656         .putcs                  = fbcon_cfb16_putcs,
657         .revc                   = fbcon_sis_revc,
658         .clear_margins          = fbcon_cfb16_clear_margins,
659         .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
660 };
661 #endif
662 #ifdef FBCON_HAS_CFB32
663 struct display_switch fbcon_sis32 = {
664         .setup                  = fbcon_cfb32_setup,
665         .bmove                  = fbcon_sis_bmove,
666         .clear                  = fbcon_sis_clear32,
667         .putc                   = fbcon_cfb32_putc,
668         .putcs                  = fbcon_cfb32_putcs,
669         .revc                   = fbcon_sis_revc,
670         .clear_margins          = fbcon_cfb32_clear_margins,
671         .fontwidthmask          = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
672 };
673 #endif
674
675 #endif /* KERNEL VERSION */
676
677