v2.4.9.9 -> v2.4.9.10
[opensuse:kernel.git] / drivers / video / sis / sis_main.c
1 /*
2  * SiS 300/630/540 frame buffer device For Kernal 2.4.x
3  *
4  * This driver is partly based on the VBE 2.0 compliant graphic 
5  * boards framebuffer driver, which is 
6  * 
7  * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
8  *
9  */
10
11 #undef  SISFBDEBUG
12
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/mm.h>
19 #include <linux/tty.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/fb.h>
23 #include <linux/console.h>
24 #include <linux/selection.h>
25 #include <linux/ioport.h>
26 #include <linux/init.h>
27 #include <linux/pci.h>
28 #include <linux/vt_kern.h>
29 #include <linux/capability.h>
30 #include <linux/sisfb.h>
31 #include <linux/fs.h>
32
33 #include <asm/io.h>
34 #include <asm/mtrr.h>
35
36 #include <video/fbcon.h>
37 #include <video/fbcon-cfb8.h>
38 #include <video/fbcon-cfb16.h>
39 #include <video/fbcon-cfb24.h>
40 #include <video/fbcon-cfb32.h>
41
42 #include "sis.h"
43 #ifdef NOBIOS
44 #include "bios.h"
45 #endif
46
47 /* ------------------- Constant Definitions ------------------------- */
48
49 /* capabilities */
50 #define TURBO_QUEUE_CAP      0x80
51 #define HW_CURSOR_CAP        0x40
52
53 /* VGA register Offsets */
54 #define SEQ_ADR                   (0x14)
55 #define SEQ_DATA                  (0x15)
56 #define DAC_ADR                   (0x18)
57 #define DAC_DATA                  (0x19)
58 #define CRTC_ADR                  (0x24)
59 #define CRTC_DATA                 (0x25)
60
61 #define DAC2_ADR                   0x16 - 0x30
62 #define DAC2_DATA                  0x17 - 0x30
63
64
65 /* SiS indexed register indexes */
66 #define IND_SIS_PASSWORD          (0x05)
67 #define IND_SIS_DRAM_SIZE         (0x14)
68 #define IND_SIS_MODULE_ENABLE     (0x1E)
69 #define IND_SIS_PCI_ADDRESS_SET   (0x20)
70 #define IND_SIS_TURBOQUEUE_ADR    (0x26)
71 #define IND_SIS_TURBOQUEUE_SET    (0x27)
72
73 /* Sis register value */
74 #define SIS_PASSWORD              (0x86)
75
76 #define SIS_2D_ENABLE             (0x40)
77
78 #define SIS_MEM_MAP_IO_ENABLE     (0x01)
79 #define SIS_PCI_ADDR_ENABLE       (0x80)
80
81 //#define MMIO_SIZE                 0x10000     /* 64K MMIO capability */
82 #define MAX_ROM_SCAN              0x10000
83
84 #define RESERVED_MEM_SIZE_4M      0x400000      /* 4M */
85 #define RESERVED_MEM_SIZE_8M      0x800000      /* 8M */
86
87 /* Mode set stuff */
88 #define DEFAULT_MODE         0  /* 640x480x8 */
89 #define DEFAULT_LCDMODE      9  /* 800x600x8 */
90 #define DEFAULT_TVMODE       9  /* 800x600x8 */
91
92 /* heap stuff */
93 #define OH_ALLOC_SIZE         4000
94 #define SENTINEL              0x7fffffff
95
96 #define TURBO_QUEUE_AREA_SIZE 0x80000   /* 512K */
97 #define HW_CURSOR_AREA_SIZE   0x1000    /* 4K */
98
99 /* ------------------- Global Variables ----------------------------- */
100
101 struct video_info ivideo;
102 HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0};
103
104 struct GlyInfo {
105         unsigned char ch;
106         int fontwidth;
107         int fontheight;
108         u8 gmask[72];
109         int ngmask;
110 };
111
112 /* Supported SiS Chips list */
113 static struct board {
114         u16 vendor, device;
115         const char *name;
116 } dev_list[] = {
117         {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     "SIS 300"},
118         {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
119         {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
120         {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"},
121         {0, 0, NULL}
122 };
123
124 /* card parameters */
125 unsigned long rom_base;
126 unsigned long rom_vbase;
127
128 /* mode */
129 static int video_type = FB_TYPE_PACKED_PIXELS;
130 static int video_linelength;
131 static int video_cmap_len;
132 static int sisfb_off = 0;
133 static int crt1off = 0;
134
135 static struct fb_var_screeninfo default_var = {
136         0, 0, 0, 0,
137         0, 0,
138         0,
139         0,
140         {0, 8, 0},
141         {0, 8, 0},
142         {0, 8, 0},
143         {0, 0, 0},
144         0,
145         FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
146         0,
147         FB_VMODE_NONINTERLACED,
148         {0, 0, 0, 0, 0, 0}
149 };
150
151 static struct display disp;
152 static struct fb_info fb_info;
153 static struct {
154         u16 blue, green, red, pad;
155 } palette[256];
156 static union {
157 #ifdef FBCON_HAS_CFB16
158         u16 cfb16[16];
159 #endif
160 #ifdef FBCON_HAS_CFB24
161         u32 cfb24[16];
162 #endif
163 #ifdef FBCON_HAS_CFB32
164         u32 cfb32[16];
165 #endif
166 } fbcon_cmap;
167
168 static int inverse = 0;
169 static int currcon = 0;
170
171 static struct display_switch sisfb_sw;
172
173 static u8 caps = 0;
174 static unsigned long MMIO_SIZE = 0;
175
176 /* ModeSet stuff */
177 unsigned char  uDispType = 0;
178 int mode_idx = -1;
179 u8 mode_no = 0;
180 u8 rate_idx = 0;
181
182 static const struct _sisbios_mode {
183         char name[15];
184         u8 mode_no;
185         u16 xres;
186         u16 yres;
187         u16 bpp;
188         u16 rate_idx;
189         u16 cols;
190         u16 rows;
191 } sisbios_mode[] = {
192         {"640x480x8",    0x2E,  640,  480,  8, 1,  80, 30},
193         {"640x480x16",   0x44,  640,  480, 16, 1,  80, 30},
194         {"640x480x32",   0x62,  640,  480, 32, 1,  80, 30},
195         {"720x480x8",    0x31,  720,  480,  8, 1,  90, 30},     /* NTSC TV */
196         {"720x480x16",   0x33,  720,  480, 16, 1,  90, 30}, 
197         {"720x480x32",   0x35,  720,  480, 32, 1,  90, 30}, 
198         {"720x576x8",    0x32,  720,  576,  8, 1,  90, 36},     /* PAL TV */
199         {"720x576x16",   0x34,  720,  576, 16, 1,  90, 36}, 
200         {"720x576x32",   0x36,  720,  576, 32, 1,  90, 36}, 
201         {"800x600x8",    0x30,  800,  600,  8, 2, 100, 37},
202         {"800x600x16",   0x47,  800,  600, 16, 2, 100, 37},
203         {"800x600x32",   0x63,  800,  600, 32, 2, 100, 37}, 
204         {"1024x768x8",   0x38, 1024,  768,  8, 2, 128, 48},
205         {"1024x768x16",  0x4A, 1024,  768, 16, 2, 128, 48},
206         {"1024x768x32",  0x64, 1024,  768, 32, 2, 128, 48},
207         {"1280x1024x8",  0x3A, 1280, 1024,  8, 2, 160, 64},
208         {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
209         {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
210         {"1600x1200x8",  0x3C, 1600, 1200,  8, 1, 200, 75},
211         {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
212         {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
213         {"1920x1440x8",  0x68, 1920, 1440,  8, 1, 240, 75},
214         {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
215         {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
216         {"\0", 0x00, 0, 0, 0, 0, 0, 0}
217 };
218
219 static struct _vrate {
220         u16 idx;
221         u16 xres;
222         u16 yres;
223         u16 refresh;
224 } vrate[] = {
225         {1,  640,  480,  60}, {2,  640, 480,  72}, {3,  640, 480,  75}, {4,  640, 480,  85},
226         {5,  640,  480, 100}, {6,  640, 480, 120}, {7,  640, 480, 160}, {8,  640, 480, 200},
227         {1,  720,  480,  60},
228         {1,  720,  576,  50},
229         {1,  800,  600,  56}, {2,  800, 600,  60}, {3,  800, 600,  72}, {4,  800, 600,  75},
230         {5,  800,  600,  85}, {6,  800, 600, 100}, {7,  800, 600, 120}, {8,  800, 600, 160},
231         {1, 1024,  768,  43}, {2, 1024, 768,  60}, {3, 1024, 768,  70}, {4, 1024, 768,  75},
232         {5, 1024,  768,  85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
233         {1, 1280, 1024,  43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
234         {1, 1600, 1200,  60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
235         {5, 1600, 1200,  85},
236         {1, 1920, 1440,  60},
237         {0, 0, 0, 0}
238 };
239
240
241 /* HEAP stuff */
242
243 struct OH {
244         struct OH *pohNext;
245         struct OH *pohPrev;
246         unsigned long ulOffset;
247         unsigned long ulSize;
248 };
249
250 struct OHALLOC {
251         struct OHALLOC *pohaNext;
252         struct OH aoh[1];
253 };
254
255 struct HEAP {
256         struct OH ohFree;
257         struct OH ohUsed;
258         struct OH *pohFreeList;
259         struct OHALLOC *pohaChain;
260
261         unsigned long ulMaxFreeSize;
262 };
263
264 struct HEAP heap;
265 unsigned long heap_start;
266 unsigned long heap_end;
267 unsigned long heap_size;
268
269 unsigned int tqueue_pos;
270 unsigned long hwcursor_vbase;
271
272
273 /* -------------------- Macro definitions --------------------------- */
274
275 #ifdef SISFBDEBUG
276 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
277 #else
278 #define DPRINTK(fmt, args...)
279 #endif
280
281 #define vgawb(reg,data) \
282            (outb(data, ivideo.vga_base+reg))
283 #define vgaww(reg,data) \
284            (outw(data, ivideo.vga_base+reg))
285 #define vgawl(reg,data) \
286            (outl(data, ivideo.vga_base+reg))
287 #define vgarb(reg)      \
288            (inb(ivideo.vga_base+reg))
289
290 /* ---------------------- Routine Prototype ------------------------- */
291
292 /* Interface used by the world */
293 int sisfb_setup(char *options);
294 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
295                          struct fb_info *info);
296 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
297                          struct fb_info *info);
298 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
299                          struct fb_info *info);
300 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
301                           struct fb_info *info);
302 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
303                           struct fb_info *info);
304 static int sisfb_ioctl(struct inode *inode, struct file *file,
305                        unsigned int cmd, unsigned long arg, int con,
306                        struct fb_info *info);
307
308 /* Interface to the low level console driver */
309 int sisfb_init(void);
310 static int sisfb_update_var(int con, struct fb_info *info);
311 static int sisfb_switch(int con, struct fb_info *info);
312 static void sisfb_blank(int blank, struct fb_info *info);
313
314 /* Internal routines */
315 static void crtc_to_var(struct fb_var_screeninfo *var);
316 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
317 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
318                          unsigned *blue, unsigned *transp,
319                          struct fb_info *fb_info);
320 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
321                          unsigned blue, unsigned transp,
322                          struct fb_info *fb_info);
323 static void do_install_cmap(int con, struct fb_info *info);
324 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
325                       struct fb_info *info);
326
327 /* set-mode routines */
328 void SetReg1(u16 port, u16 index, u16 data);
329 void SetReg3(u16 port, u16 data);
330 void SetReg4(u16 port, unsigned long data);
331 u8 GetReg1(u16 port, u16 index);
332 u8 GetReg2(u16 port);
333 u32 GetReg3(u16 port);
334 extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
335                                 USHORT ModeNo);
336 extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
337 static void pre_setmode(void);
338 static void post_setmode(void);
339 static void search_mode(const char *name);
340 static u8 search_refresh_rate(unsigned int rate);
341
342 /* heap routines */
343 static int sisfb_heap_init(void);
344 static struct OH *poh_new_node(void);
345 static struct OH *poh_allocate(unsigned long size);
346 static struct OH *poh_free(unsigned long base);
347 static void delete_node(struct OH *poh);
348 static void insert_node(struct OH *pohList, struct OH *poh);
349 static void free_node(struct OH *poh);
350
351 /* ---------------------- Internal Routines ------------------------- */
352
353 inline static u32 RD32(unsigned char *base, s32 off)
354 {
355         return readl(base + off);
356 }
357
358 inline static void WR32(unsigned char *base, s32 off, u32 v)
359 {
360         writel(v, base + off);
361 }
362
363 inline static void WR16(unsigned char *base, s32 off, u16 v)
364 {
365         writew(v, base + off);
366 }
367
368 inline static void WR8(unsigned char *base, s32 off, u8 v)
369 {
370         writeb(v, base + off);
371 }
372
373 inline static u32 regrl(s32 off)
374 {
375         return RD32(ivideo.mmio_vbase, off);
376 }
377
378 inline static void regwl(s32 off, u32 v)
379 {
380         WR32(ivideo.mmio_vbase, off, v);
381 }
382
383 inline static void regww(s32 off, u16 v)
384 {
385         WR16(ivideo.mmio_vbase, off, v);
386 }
387
388 inline static void regwb(s32 off, u8 v)
389 {
390         WR8(ivideo.mmio_vbase, off, v);
391 }
392
393 /* 
394  *    Get CRTC registers to set var 
395  */
396 static void crtc_to_var(struct fb_var_screeninfo *var)
397 {
398         u16 VRE, VBE, VRS, VBS, VDE, VT;
399         u16 HRE, HBE, HRS, HBS, HDE, HT;
400         u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
401         int A, B, C, D, E, F, temp;
402         double hrate, drate;
403
404         vgawb(SEQ_ADR, 0x6);
405         uSRdata = vgarb(SEQ_DATA);
406
407         if (uSRdata & 0x20)
408                 var->vmode = FB_VMODE_INTERLACED;
409         else
410                 var->vmode = FB_VMODE_NONINTERLACED;
411
412         switch ((uSRdata & 0x1c) >> 2) {
413         case 0:
414                 var->bits_per_pixel = 8;
415                 break;
416         case 2:
417                 var->bits_per_pixel = 16;
418                 break;
419         case 4:
420                 var->bits_per_pixel = 32;
421                 break;
422         }
423
424         switch (var->bits_per_pixel) {
425         case 8:
426                 var->red.length = 6;
427                 var->green.length = 6;
428                 var->blue.length = 6;
429                 video_cmap_len = 256;
430                 break;
431         case 16:                /* RGB 565 */
432                 var->red.offset = 11;
433                 var->red.length = 5;
434                 var->green.offset = 5;
435                 var->green.length = 6;
436                 var->blue.offset = 0;
437                 var->blue.length = 5;
438                 var->transp.offset = 0;
439                 var->transp.length = 0;
440                 video_cmap_len = 16;
441
442                 break;
443         case 24:                /* RGB 888 */
444                 var->red.offset = 16;
445                 var->red.length = 8;
446                 var->green.offset = 8;
447                 var->green.length = 8;
448                 var->blue.offset = 0;
449                 var->blue.length = 8;
450                 var->transp.offset = 0;
451                 var->transp.length = 0;
452                 video_cmap_len = 16;
453                 break;
454         case 32:
455                 var->red.offset = 16;
456                 var->red.length = 8;
457                 var->green.offset = 8;
458                 var->green.length = 8;
459                 var->blue.offset = 0;
460                 var->blue.length = 8;
461                 var->transp.offset = 24;
462                 var->transp.length = 8;
463                 video_cmap_len = 16;
464                 break;
465         }
466
467         vgawb(SEQ_ADR, 0xa);
468         uSRdata = vgarb(SEQ_DATA);
469
470         vgawb(CRTC_ADR, 0x6);
471         uCRdata = vgarb(CRTC_DATA);
472         vgawb(CRTC_ADR, 0x7);
473         uCRdata2 = vgarb(CRTC_DATA);
474         VT =
475             (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
476             ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
477                                               10);
478         A = VT + 2;
479
480         vgawb(CRTC_ADR, 0x12);
481         uCRdata = vgarb(CRTC_DATA);
482         VDE =
483             (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
484             ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
485         E = VDE + 1;
486
487         vgawb(CRTC_ADR, 0x10);
488         uCRdata = vgarb(CRTC_DATA);
489         VRS =
490             (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
491             ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
492         F = VRS + 1 - E;
493
494         vgawb(CRTC_ADR, 0x15);
495         uCRdata = vgarb(CRTC_DATA);
496         vgawb(CRTC_ADR, 0x9);
497         uCRdata3 = vgarb(CRTC_DATA);
498         VBS =
499             (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
500             ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
501
502         vgawb(CRTC_ADR, 0x16);
503         uCRdata = vgarb(CRTC_DATA);
504         VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
505         temp = VBE - ((E - 1) & 511);
506         B = (temp > 0) ? temp : (temp + 512);
507
508         vgawb(CRTC_ADR, 0x11);
509         uCRdata = vgarb(CRTC_DATA);
510         VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
511         temp = VRE - ((E + F - 1) & 31);
512         C = (temp > 0) ? temp : (temp + 32);
513
514         D = B - F - C;
515
516         var->yres = var->yres_virtual = E;
517         var->upper_margin = D;
518         var->lower_margin = F;
519         var->vsync_len = C;
520
521         vgawb(SEQ_ADR, 0xb);
522         uSRdata = vgarb(SEQ_DATA);
523
524         vgawb(CRTC_ADR, 0x0);
525         uCRdata = vgarb(CRTC_DATA);
526         HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
527         A = HT + 5;
528
529         vgawb(CRTC_ADR, 0x1);
530         uCRdata = vgarb(CRTC_DATA);
531         HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
532         E = HDE + 1;
533
534         vgawb(CRTC_ADR, 0x4);
535         uCRdata = vgarb(CRTC_DATA);
536         HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
537         F = HRS - E - 3;
538
539         vgawb(CRTC_ADR, 0x2);
540         uCRdata = vgarb(CRTC_DATA);
541         HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
542
543         vgawb(SEQ_ADR, 0xc);
544         uSRdata = vgarb(SEQ_DATA);
545         vgawb(CRTC_ADR, 0x3);
546         uCRdata = vgarb(CRTC_DATA);
547         vgawb(CRTC_ADR, 0x5);
548         uCRdata2 = vgarb(CRTC_DATA);
549         HBE =
550             (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
551             ((u16) (uSRdata & 0x03) << 6);
552         HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
553
554         temp = HBE - ((E - 1) & 255);
555         B = (temp > 0) ? temp : (temp + 256);
556
557         temp = HRE - ((E + F + 3) & 63);
558         C = (temp > 0) ? temp : (temp + 64);
559
560         D = B - F - C;
561
562         var->xres = var->xres_virtual = E * 8;
563         var->left_margin = D * 8;
564         var->right_margin = F * 8;
565         var->hsync_len = C * 8;
566
567         var->activate = FB_ACTIVATE_NOW;
568
569         var->sync = 0;
570
571         uMRdata = vgarb(0x1C);
572         if (uMRdata & 0x80)
573                 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
574         else
575                 var->sync |= FB_SYNC_VERT_HIGH_ACT;
576
577         if (uMRdata & 0x40)
578                 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
579         else
580                 var->sync |= FB_SYNC_HOR_HIGH_ACT;
581
582         VT += 2;
583         VT <<= 1;
584         HT = (HT + 5) * 8;
585
586         hrate = (double) ivideo.refresh_rate * (double) VT / 2;
587         drate = hrate * HT;
588         var->pixclock = (u32) (1E12 / drate);
589 }
590
591 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
592 {
593         struct fb_fix_screeninfo fix;
594         struct display *display;
595         struct display_switch *sw;
596         long flags;
597
598         if (con >= 0)
599                 display = &fb_display[con];
600         else
601                 display = &disp;        /* used during initialization */
602
603         sisfb_get_fix(&fix, con, 0);
604
605         display->screen_base = ivideo.video_vbase;
606         display->visual = fix.visual;
607         display->type = fix.type;
608         display->type_aux = fix.type_aux;
609         display->ypanstep = fix.ypanstep;
610         display->ywrapstep = fix.ywrapstep;
611         display->line_length = fix.line_length;
612         display->next_line = fix.line_length;
613         /*display->can_soft_blank = 1; */
614         display->can_soft_blank = 0;
615         display->inverse = inverse;
616         display->var = *var;
617
618         save_flags(flags);
619         switch (ivideo.video_bpp) {
620 #ifdef FBCON_HAS_CFB8
621         case 8:
622                 sw = &fbcon_cfb8;
623                 break;
624 #endif
625 #ifdef FBCON_HAS_CFB16
626         case 15:
627         case 16:
628                 sw = &fbcon_cfb16;
629                 display->dispsw_data = fbcon_cmap.cfb16;
630                 break;
631 #endif
632 #ifdef FBCON_HAS_CFB24
633         case 24:
634                 sw = &fbcon_cfb24;
635                 display->dispsw_data = fbcon_cmap.cfb24;
636                 break;
637 #endif
638 #ifdef FBCON_HAS_CFB32
639         case 32:
640                 sw = &fbcon_cfb32;
641                 display->dispsw_data = fbcon_cmap.cfb32;
642                 break;
643 #endif
644         default:
645                 sw = &fbcon_dummy;
646                 return;
647         }
648         memcpy(&sisfb_sw, sw, sizeof(*sw));
649         display->dispsw = &sisfb_sw;
650         restore_flags(flags);
651
652         display->scrollmode = SCROLL_YREDRAW;
653         sisfb_sw.bmove = fbcon_redraw_bmove;
654
655 }
656
657 /*
658  *    Read a single color register and split it into colors/transparent. 
659  *    Return != 0 for invalid regno.
660  */
661 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
662                          unsigned *transp, struct fb_info *fb_info)
663 {
664         if (regno >= video_cmap_len)
665                 return 1;
666
667         *red = palette[regno].red;
668         *green = palette[regno].green;
669         *blue = palette[regno].blue;
670         *transp = 0;
671         return 0;
672 }
673
674 /*
675  *    Set a single color register. The values supplied are already
676  *    rounded down to the hardware's capabilities (according to the
677  *    entries in the var structure). Return != 0 for invalid regno.
678  */
679 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
680                          unsigned transp, struct fb_info *fb_info)
681 {
682
683         if (regno >= video_cmap_len)
684                 return 1;
685
686         palette[regno].red = red;
687         palette[regno].green = green;
688         palette[regno].blue = blue;
689
690         switch (ivideo.video_bpp) {
691 #ifdef FBCON_HAS_CFB8
692         case 8:
693                 vgawb(DAC_ADR, regno);
694                 vgawb(DAC_DATA, red >> 10);
695                 vgawb(DAC_DATA, green >> 10);
696                 vgawb(DAC_DATA, blue >> 10);
697                 if(uDispType & MASK_DISPTYPE_DISP2)
698                 {
699                         /* VB connected */
700                         vgawb(DAC2_ADR,  regno);
701                         vgawb(DAC2_DATA, red   >> 8);
702                         vgawb(DAC2_DATA, green >> 8);
703                         vgawb(DAC2_DATA, blue  >> 8);
704                 }
705
706                 break;
707 #endif
708 #ifdef FBCON_HAS_CFB16
709         case 15:
710         case 16:
711                 fbcon_cmap.cfb16[regno] =
712                     ((red & 0xf800)) |
713                     ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
714                 break;
715 #endif
716 #ifdef FBCON_HAS_CFB24
717         case 24:
718                 red >>= 8;
719                 green >>= 8;
720                 blue >>= 8;
721                 fbcon_cmap.cfb24[regno] =
722                     (red << 16) | (green << 8) | (blue);
723                 break;
724 #endif
725 #ifdef FBCON_HAS_CFB32
726         case 32:
727                 red >>= 8;
728                 green >>= 8;
729                 blue >>= 8;
730                 fbcon_cmap.cfb32[regno] =
731                     (red << 16) | (green << 8) | (blue);
732                 break;
733 #endif
734         }
735         return 0;
736 }
737
738 static void do_install_cmap(int con, struct fb_info *info)
739 {
740         if (con != currcon)
741                 return;
742
743         if (fb_display[con].cmap.len)
744                 fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
745         else
746                 fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
747                             sis_setcolreg, info);
748 }
749
750 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
751                       struct fb_info *info)
752 {
753         unsigned int htotal =
754             var->left_margin + var->xres + var->right_margin +
755             var->hsync_len;
756         unsigned int vtotal =
757             var->upper_margin + var->yres + var->lower_margin +
758             var->vsync_len;
759         double drate = 0, hrate = 0;
760         int found_mode = 0;
761         int old_mode;
762
763         if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
764                 vtotal <<= 1;
765         else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
766                 vtotal <<= 2;
767         else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
768                 var->yres <<= 1;
769
770
771         if (!htotal || !vtotal) {
772                 DPRINTK("Invalid 'var' Information!\n");
773                 return 1;
774         }
775
776         drate = 1E12 / var->pixclock;
777         hrate = drate / htotal;
778         ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
779
780         old_mode = mode_idx;
781         mode_idx = 0;
782
783         while ((sisbios_mode[mode_idx].mode_no != 0)
784                && (sisbios_mode[mode_idx].xres <= var->xres)) {
785                 if ((sisbios_mode[mode_idx].xres == var->xres)
786                     && (sisbios_mode[mode_idx].yres == var->yres)
787                     && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
788                         mode_no = sisbios_mode[mode_idx].mode_no;
789                         found_mode = 1;
790                         break;
791                 }
792                 mode_idx++;
793         }
794
795         if(found_mode)
796         {
797                 switch(uDispType & MASK_DISPTYPE_DISP2)
798                 {
799                 case MASK_DISPTYPE_LCD:
800                         switch(HwExt.usLCDType)
801                         {
802                         case LCD1024:
803                                 if(var->xres > 1024)
804                                         found_mode = 0;
805                                 break;
806                         case LCD1280:
807                                 if(var->xres > 1280)
808                                         found_mode = 0;
809                                 break;
810                         case LCD2048:
811                                 if(var->xres > 2048)
812                                         found_mode = 0;
813                                 break;
814                         case LCD1920:
815                                 if(var->xres > 1920)
816                                         found_mode = 0;
817                                 break;
818                         case LCD1600:
819                                 if(var->xres > 1600)
820                                         found_mode = 0;
821                                 break;
822                         case LCD800:
823                                 if(var->xres > 800)
824                                         found_mode = 0;
825                                 break;
826                         case LCD640:
827                                 if(var->xres > 640)
828                                         found_mode = 0;
829                                 break;
830                         default:
831                                 found_mode = 0;
832                         }
833                         if(var->xres == 720)    /* mode only for TV */
834                                 found_mode = 0; 
835                         break;
836                 case MASK_DISPTYPE_TV:
837                         switch(var->xres)
838                         {
839                         case 800:
840                         case 640:
841                                 break;
842                         case 720:
843                                 if(ivideo.TV_type == TVMODE_NTSC)
844                                 {
845                                         if(sisbios_mode[mode_idx].yres != 480)
846                                                 found_mode = 0;
847                                 }
848                                 else if(ivideo.TV_type == TVMODE_PAL)
849                                 {
850                                         if(sisbios_mode[mode_idx].yres != 576)
851                                                 found_mode = 0;
852                                 }
853                                 break;
854                         default:
855                                 /* illegal mode */
856                                 found_mode = 0;
857                         }
858                         break;
859                 }
860         }
861
862         if (!found_mode) {
863                 printk("sisfb does not support mode %dx%d-%d\n", var->xres,
864                        var->yres, var->bits_per_pixel);
865                 mode_idx = old_mode;
866                 return 1;
867         }
868
869         if (search_refresh_rate(ivideo.refresh_rate) == 0) {
870                 /* not supported rate */
871                 rate_idx = sisbios_mode[mode_idx].rate_idx;
872                 ivideo.refresh_rate = 60;
873         }
874
875         if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
876                 pre_setmode();
877
878                 if (SiSSetMode(&HwExt, mode_no)) {
879                         DPRINTK("sisfb: set mode[0x%x]: failed\n",
880                                 mode_no);
881                         return 1;
882                 }
883
884                 post_setmode();
885
886                 printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres, 
887                         sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate);
888
889                 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
890                 ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
891                 ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
892                 ivideo.org_x = ivideo.org_y = 0;
893                 video_linelength =
894                     ivideo.video_width * (ivideo.video_bpp >> 3);
895
896                 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
897                         ivideo.video_width, ivideo.video_height,
898                         ivideo.video_bpp, video_linelength);
899         }
900
901         return 0;
902 }
903
904 /* ---------------------- Draw Funtions ----------------------------- */
905
906 static void sis_get_glyph(struct GlyInfo *gly)
907 {
908         struct display *p = &fb_display[currcon];
909         u16 c;
910         u8 *cdat;
911         int widthb;
912         u8 *gbuf = gly->gmask;
913         int size;
914
915
916         gly->fontheight = fontheight(p);
917         gly->fontwidth = fontwidth(p);
918         widthb = (fontwidth(p) + 7) / 8;
919
920         c = gly->ch & p->charmask;
921         if (fontwidth(p) <= 8)
922                 cdat = p->fontdata + c * fontheight(p);
923         else
924                 cdat = p->fontdata + (c * fontheight(p) << 1);
925
926         size = fontheight(p) * widthb;
927         memcpy(gbuf, cdat, size);
928         gly->ngmask = size;
929 }
930
931
932 /* ---------------------- HEAP Routines ----------------------------- */
933
934 /* 
935  *  Heap Initialization
936  */
937
938 static int sisfb_heap_init(void)
939 {
940         struct OH *poh;
941         u8 jTemp, tq_state;
942
943         if(ivideo.video_size > 0x800000)
944                 /* video ram is large than 8M */
945                 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
946         else
947                 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
948
949         heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
950         heap_size = heap_end - heap_start;
951
952
953         /* Setting for Turbo Queue */
954         if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
955                 tqueue_pos =
956                     (ivideo.video_size -
957                      TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
958                 jTemp = (u8) (tqueue_pos & 0xff);
959                 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
960                 tq_state = vgarb(SEQ_DATA);
961                 tq_state |= 0xf0;
962                 tq_state &= 0xfc;
963                 tq_state |= (u8) (tqueue_pos >> 8);
964                 vgawb(SEQ_DATA, tq_state);
965                 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
966                 vgawb(SEQ_DATA, jTemp);
967
968                 caps |= TURBO_QUEUE_CAP;
969
970                 heap_end -= TURBO_QUEUE_AREA_SIZE;
971                 heap_size -= TURBO_QUEUE_AREA_SIZE;
972         }
973
974         /* Setting for HW cursor(4K) */
975         if (heap_size >= HW_CURSOR_AREA_SIZE) {
976                 heap_end -= HW_CURSOR_AREA_SIZE;
977                 heap_size -= HW_CURSOR_AREA_SIZE;
978                 hwcursor_vbase = heap_end;
979
980                 caps |= HW_CURSOR_CAP;
981         }
982
983         heap.pohaChain = NULL;
984         heap.pohFreeList = NULL;
985
986         poh = poh_new_node();
987
988         if (poh == NULL)
989                 return 1;
990
991         /* The first node describles the entire heap size */
992         poh->pohNext = &heap.ohFree;
993         poh->pohPrev = &heap.ohFree;
994         poh->ulSize = heap_end - heap_start + 1;
995         poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
996
997         DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
998                 (char *) heap_start, (char *) heap_end,
999                 (unsigned int) poh->ulSize / 1024);
1000
1001         DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1002                 (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
1003
1004         /* The second node in our free list sentinel */
1005         heap.ohFree.pohNext = poh;
1006         heap.ohFree.pohPrev = poh;
1007         heap.ohFree.ulSize = 0;
1008         heap.ulMaxFreeSize = poh->ulSize;
1009
1010         /* Initialize the discardable list */
1011         heap.ohUsed.pohNext = &heap.ohUsed;
1012         heap.ohUsed.pohPrev = &heap.ohUsed;
1013         heap.ohUsed.ulSize = SENTINEL;
1014
1015         return 0;
1016 }
1017
1018 /*
1019  *  Allocates a basic memory unit in which we'll pack our data structures.
1020  */
1021
1022 static struct OH *poh_new_node(void)
1023 {
1024         int i;
1025         unsigned long cOhs;
1026         struct OHALLOC *poha;
1027         struct OH *poh;
1028
1029         if (heap.pohFreeList == NULL) {
1030                 poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
1031                 if (!poha)
1032                         return NULL;
1033
1034                 poha->pohaNext = heap.pohaChain;
1035                 heap.pohaChain = poha;
1036
1037                 cOhs =
1038                     (OH_ALLOC_SIZE -
1039                      sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
1040
1041                 poh = &poha->aoh[0];
1042                 for (i = cOhs - 1; i != 0; i--) {
1043                         poh->pohNext = poh + 1;
1044                         poh = poh + 1;
1045                 }
1046
1047                 poh->pohNext = NULL;
1048                 heap.pohFreeList = &poha->aoh[0];
1049         }
1050
1051         poh = heap.pohFreeList;
1052         heap.pohFreeList = poh->pohNext;
1053
1054         return (poh);
1055 }
1056
1057 /* 
1058  *  Allocates space, return NULL when failed
1059  */
1060
1061 static struct OH *poh_allocate(unsigned long size)
1062 {
1063         struct OH *pohThis;
1064         struct OH *pohRoot;
1065         int bAllocated = 0;
1066
1067         if (size > heap.ulMaxFreeSize) {
1068                 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1069                         (unsigned int) size / 1024);
1070                 return (NULL);
1071         }
1072
1073         pohThis = heap.ohFree.pohNext;
1074
1075         while (pohThis != &heap.ohFree) {
1076                 if (size <= pohThis->ulSize) {
1077                         bAllocated = 1;
1078                         break;
1079                 }
1080                 pohThis = pohThis->pohNext;
1081         }
1082
1083         if (!bAllocated) {
1084                 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1085                         (unsigned int) size / 1024);
1086                 return (NULL);
1087         }
1088
1089         if (size == pohThis->ulSize) {
1090                 pohRoot = pohThis;
1091                 delete_node(pohThis);
1092         } else {
1093                 pohRoot = poh_new_node();
1094
1095                 if (pohRoot == NULL) {
1096                         return (NULL);
1097                 }
1098
1099                 pohRoot->ulOffset = pohThis->ulOffset;
1100                 pohRoot->ulSize = size;
1101
1102                 pohThis->ulOffset += size;
1103                 pohThis->ulSize -= size;
1104         }
1105
1106         heap.ulMaxFreeSize -= size;
1107
1108         pohThis = &heap.ohUsed;
1109         insert_node(pohThis, pohRoot);
1110
1111         return (pohRoot);
1112 }
1113
1114 /* 
1115  *  To remove a node from a list.
1116  */
1117
1118 static void delete_node(struct OH *poh)
1119 {
1120         struct OH *pohPrev;
1121         struct OH *pohNext;
1122
1123
1124         pohPrev = poh->pohPrev;
1125         pohNext = poh->pohNext;
1126
1127         pohPrev->pohNext = pohNext;
1128         pohNext->pohPrev = pohPrev;
1129
1130         return;
1131 }
1132
1133 /* 
1134  *  To insert a node into a list.
1135  */
1136
1137 static void insert_node(struct OH *pohList, struct OH *poh)
1138 {
1139         struct OH *pohTemp;
1140
1141         pohTemp = pohList->pohNext;
1142
1143         pohList->pohNext = poh;
1144         pohTemp->pohPrev = poh;
1145
1146         poh->pohPrev = pohList;
1147         poh->pohNext = pohTemp;
1148 }
1149
1150 /*
1151  *  Frees an off-screen heap allocation.
1152  */
1153
1154 static struct OH *poh_free(unsigned long base)
1155 {
1156
1157         struct OH *pohThis;
1158         struct OH *pohFreed;
1159         struct OH *pohPrev;
1160         struct OH *pohNext;
1161         unsigned long ulUpper;
1162         unsigned long ulLower;
1163         int foundNode = 0;
1164
1165         pohFreed = heap.ohUsed.pohNext;
1166
1167         while (pohFreed != &heap.ohUsed) {
1168                 if (pohFreed->ulOffset == base) {
1169                         foundNode = 1;
1170                         break;
1171                 }
1172
1173                 pohFreed = pohFreed->pohNext;
1174         }
1175
1176         if (!foundNode)
1177                 return (NULL);
1178
1179         heap.ulMaxFreeSize += pohFreed->ulSize;
1180
1181         pohPrev = pohNext = NULL;
1182         ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
1183         ulLower = pohFreed->ulOffset;
1184
1185         pohThis = heap.ohFree.pohNext;
1186
1187         while (pohThis != &heap.ohFree) {
1188                 if (pohThis->ulOffset == ulUpper) {
1189                         pohNext = pohThis;
1190                 }
1191                         else if ((pohThis->ulOffset + pohThis->ulSize) ==
1192                                  ulLower) {
1193                         pohPrev = pohThis;
1194                 }
1195                 pohThis = pohThis->pohNext;
1196         }
1197
1198         delete_node(pohFreed);
1199
1200         if (pohPrev && pohNext) {
1201                 pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
1202                 delete_node(pohNext);
1203                 free_node(pohFreed);
1204                 free_node(pohNext);
1205                 return (pohPrev);
1206         }
1207
1208         if (pohPrev) {
1209                 pohPrev->ulSize += pohFreed->ulSize;
1210                 free_node(pohFreed);
1211                 return (pohPrev);
1212         }
1213
1214         if (pohNext) {
1215                 pohNext->ulSize += pohFreed->ulSize;
1216                 pohNext->ulOffset = pohFreed->ulOffset;
1217                 free_node(pohFreed);
1218                 return (pohNext);
1219         }
1220
1221         insert_node(&heap.ohFree, pohFreed);
1222
1223         return (pohFreed);
1224 }
1225
1226 /*
1227  *  Frees our basic data structure allocation unit by adding it to a free
1228  *  list.
1229  */
1230
1231 static void free_node(struct OH *poh)
1232 {
1233         if (poh == NULL) {
1234                 return;
1235         }
1236
1237         poh->pohNext = heap.pohFreeList;
1238         heap.pohFreeList = poh;
1239
1240         return;
1241 }
1242
1243 void sis_malloc(struct sis_memreq *req)
1244 {
1245         struct OH *poh;
1246
1247         poh = poh_allocate(req->size);
1248
1249         if (poh == NULL) {
1250                 req->offset = 0;
1251                 req->size = 0;
1252                 DPRINTK("sisfb: VMEM Allocation Failed\n");
1253         } else {
1254                 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1255                         (char *) (poh->ulOffset +
1256                                   (unsigned long) ivideo.video_vbase));
1257
1258                 req->offset = poh->ulOffset;
1259                 req->size = poh->ulSize;
1260         }
1261
1262 }
1263
1264 void sis_free(unsigned long base)
1265 {
1266         struct OH *poh;
1267
1268         poh = poh_free(base);
1269
1270         if (poh == NULL) {
1271                 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1272                         (unsigned int) base);
1273         }
1274 }
1275
1276 void sis_dispinfo(struct ap_data *rec)
1277 {
1278         rec->minfo.bpp    = ivideo.video_bpp;
1279         rec->minfo.xres   = ivideo.video_width;
1280         rec->minfo.yres   = ivideo.video_height;
1281         rec->minfo.v_xres = ivideo.video_vwidth;
1282         rec->minfo.v_yres = ivideo.video_vheight;
1283         rec->minfo.org_x  = ivideo.org_x;
1284         rec->minfo.org_y  = ivideo.org_y;
1285         rec->minfo.vrate  = ivideo.refresh_rate;
1286         rec->iobase       = ivideo.vga_base - 0x30;
1287         rec->mem_size     = ivideo.video_size;
1288         rec->disp_state   = ivideo.disp_state; 
1289         switch(HwExt.jChipID)
1290         {
1291         case SIS_Glamour:
1292                 rec->chip = SiS_300;
1293                 break;
1294         case SIS_Trojan:
1295                 if((HwExt.revision_id & 0xf0) == 0x30)
1296                         rec->chip = SiS_630S;
1297                 else
1298                         rec->chip = SiS_630;
1299                 break;
1300         case SIS_Spartan:
1301                 rec->chip = SiS_540;
1302                 break;
1303         case SIS_730:
1304                 rec->chip = SiS_730;
1305                 break;
1306         default:
1307                 rec->chip = SiS_UNKNOWN;
1308                 break;
1309         }
1310 }
1311
1312
1313 /* ---------------------- SetMode Routines -------------------------- */
1314
1315 void SetReg1(u16 port, u16 index, u16 data)
1316 {
1317         outb((u8) (index & 0xff), port);
1318         port++;
1319         outb((u8) (data & 0xff), port);
1320 }
1321
1322 void SetReg3(u16 port, u16 data)
1323 {
1324         outb((u8) (data & 0xff), port);
1325 }
1326
1327 void SetReg4(u16 port, unsigned long data)
1328 {
1329         outl((u32) (data & 0xffffffff), port);
1330 }
1331
1332 u8 GetReg1(u16 port, u16 index)
1333 {
1334         u8 data;
1335
1336         outb((u8) (index & 0xff), port);
1337         port += 1;
1338         data = inb(port);
1339         return (data);
1340 }
1341
1342 u8 GetReg2(u16 port)
1343 {
1344         u8 data;
1345
1346         data = inb(port);
1347
1348         return (data);
1349 }
1350
1351 u32 GetReg3(u16 port)
1352 {
1353         u32 data;
1354
1355         data = inl(port);
1356         return (data);
1357 }
1358
1359 void ClearDAC(u16 port)
1360 {
1361         int i,j;
1362
1363         vgawb(DAC_ADR, 0x00);
1364         for(i=0; i<256; i++)
1365                 for(j=0; j<3; j++)
1366                         vgawb(DAC_DATA, 0);
1367 }
1368
1369 void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt)
1370 {
1371         memset((char *) ivideo.video_vbase, 0,
1372                 video_linelength * ivideo.video_height);
1373 }
1374
1375 static void pre_setmode(void)
1376 {
1377         unsigned char  uCR30=0, uCR31=0;
1378
1379         switch(uDispType & MASK_DISPTYPE_DISP2)
1380         {
1381         case MASK_DISPTYPE_CRT2:
1382                 uCR30 = 0x41;
1383                 uCR31 = 0x40; 
1384                 break;
1385         case MASK_DISPTYPE_LCD:
1386                 uCR30 = 0x21;
1387                 uCR31 = 0x40;
1388                 break;
1389         case MASK_DISPTYPE_TV:
1390                 if(ivideo.TV_type == TVMODE_HIVISION)
1391                         uCR30 = 0x81;
1392                 else if(ivideo.TV_plug == TVPLUG_SVIDEO)
1393                         uCR30 = 0x09;
1394                 else if(ivideo.TV_plug == TVPLUG_COMPOSITE)
1395                         uCR30 = 0x05;
1396                 else if(ivideo.TV_plug == TVPLUG_SCART)
1397                         uCR30 = 0x11;
1398                 uCR31 = 0x40;  /* CR31[0] will be set in setmode() */
1399                 break;
1400         default:
1401                 uCR30 = 0x00;
1402                 uCR31 = 0x60;
1403         }
1404
1405         vgawb(CRTC_ADR, 0x30);
1406         vgawb(CRTC_DATA, uCR30);
1407         vgawb(CRTC_ADR, 0x31);
1408         vgawb(CRTC_DATA, uCR31);
1409     vgawb(CRTC_ADR, 0x33);
1410     vgawb(CRTC_DATA, rate_idx & 0x0f);
1411 }
1412
1413 static void post_setmode(void)
1414 {
1415         u8 uTemp;
1416
1417         vgawb(CRTC_ADR, 0x17);
1418         uTemp = vgarb(CRTC_DATA);
1419
1420         if(crt1off)       /* turn off CRT1 */
1421                 uTemp &= ~0x80;
1422         else          /* turn on CRT1 */
1423                 uTemp |= 0x80;
1424         vgawb(CRTC_DATA, uTemp);
1425
1426         /* disable 24-bit palette RAM and Gamma correction */
1427         vgawb(SEQ_ADR, 0x07);
1428         uTemp = vgarb(SEQ_DATA);
1429         uTemp &= ~0x04;
1430         vgawb(SEQ_DATA, uTemp);
1431 }
1432
1433 static void search_mode(const char *name)
1434 {
1435         int i = 0;
1436
1437         if (name == NULL)
1438                 return;
1439
1440         while (sisbios_mode[i].mode_no != 0) {
1441                 if (!strcmp(name, sisbios_mode[i].name)) {
1442                         mode_idx = i;
1443                         break;
1444                 }
1445                 i++;
1446         }
1447
1448         if (mode_idx < 0)
1449                 DPRINTK("Invalid user mode : %s\n", name);
1450 }
1451
1452 static u8 search_refresh_rate(unsigned int rate)
1453 {
1454         u16 xres, yres;
1455         int i = 0;
1456
1457         xres = sisbios_mode[mode_idx].xres;
1458         yres = sisbios_mode[mode_idx].yres;
1459
1460         while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
1461                 if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
1462                     && (vrate[i].refresh == rate)) {
1463                         rate_idx = vrate[i].idx;
1464                         return rate_idx;
1465                 }
1466                 i++;
1467         }
1468
1469         DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
1470                 yres);
1471
1472         return 0;
1473 }
1474
1475 /* ------------------ Public Routines ------------------------------- */
1476
1477 /*
1478  *    Get the Fixed Part of the Display
1479  */
1480
1481 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
1482                          struct fb_info *info)
1483 {
1484         DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
1485
1486         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1487         strcpy(fix->id, fb_info.modename);
1488
1489         fix->smem_start = ivideo.video_base;
1490         if(ivideo.video_size > 0x800000)
1491                 fix->smem_len = RESERVED_MEM_SIZE_8M;   /* reserved for Xserver */
1492         else
1493                 fix->smem_len = RESERVED_MEM_SIZE_4M;   /* reserved for Xserver */
1494
1495         fix->type = video_type;
1496         fix->type_aux = 0;
1497         if (ivideo.video_bpp == 8)
1498                 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1499         else
1500                 fix->visual = FB_VISUAL_TRUECOLOR;
1501         fix->xpanstep = 0;
1502         fix->ypanstep = 0;
1503         fix->ywrapstep = 0;
1504         fix->line_length = video_linelength;
1505         fix->mmio_start = ivideo.mmio_base;
1506         fix->mmio_len = MMIO_SIZE;
1507         fix->accel = FB_ACCEL_SIS_GLAMOUR;
1508         fix->reserved[0] = ivideo.video_size & 0xFFFF;
1509         fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
1510         fix->reserved[2] = caps;        /* capabilities */
1511
1512         return 0;
1513 }
1514
1515 /*
1516  *    Get the User Defined Part of the Display
1517  */
1518
1519 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
1520                          struct fb_info *info)
1521 {
1522         DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
1523
1524         if (con == -1)
1525                 memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
1526         else
1527                 *var = fb_display[con].var;
1528         return 0;
1529 }
1530
1531 /*
1532  *    Set the User Defined Part of the Display
1533  */
1534
1535 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
1536                          struct fb_info *info)
1537 {
1538         int err;
1539         unsigned int cols, rows;
1540
1541         fb_display[con].var.activate = FB_ACTIVATE_NOW;
1542
1543         /* Set mode */
1544         if (do_set_var(var, con == currcon, info)) {
1545                 crtc_to_var(var);       /* return current mode to user */
1546                 return -EINVAL;
1547         }
1548
1549         /* get actual setting value */
1550         crtc_to_var(var);
1551
1552         /* update display of current console */
1553         sisfb_set_disp(con, var);
1554
1555         if (info->changevar)
1556                 (*info->changevar) (con);
1557
1558         if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
1559                 return err;
1560
1561         do_install_cmap(con, info);
1562
1563         /* inform console to update struct display */
1564         cols = sisbios_mode[mode_idx].cols;
1565         rows = sisbios_mode[mode_idx].rows;
1566         vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1567
1568         return 0;
1569 }
1570
1571
1572 /*
1573  *    Get the Colormap
1574  */
1575
1576 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1577                           struct fb_info *info)
1578 {
1579         DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
1580
1581         if (con == currcon)
1582                 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1583         else if (fb_display[con].cmap.len)      /* non default colormap? */
1584                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1585         else
1586                 fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
1587         return 0;
1588 }
1589
1590 /*
1591  *    Set the Colormap
1592  */
1593
1594 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1595                           struct fb_info *info)
1596 {
1597         int err;
1598
1599         if (!fb_display[con].cmap.len) {        /* no colormap allocated */
1600                 err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
1601                 if (err)
1602                         return err;
1603         }
1604         if (con == currcon)     /* current console */
1605                 return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
1606         else
1607                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1608         return 0;
1609 }
1610
1611 static int sisfb_ioctl(struct inode *inode, struct file *file,
1612                        unsigned int cmd, unsigned long arg, int con,
1613                        struct fb_info *info)
1614 {
1615         switch (cmd) {
1616         case FBIO_ALLOC:
1617                 if(!capable(CAP_SYS_RAWIO))
1618                         return -EPERM;
1619                 sis_malloc((struct sis_memreq *) arg);
1620                 break;
1621         case FBIO_FREE:
1622                 if(!capable(CAP_SYS_RAWIO))
1623                         return -EPERM;
1624                 sis_free(*(unsigned long *) arg);
1625                 break;
1626         case FBIOGET_GLYPH:
1627                 sis_get_glyph((struct GlyInfo *) arg);
1628                 break;
1629         case FBIOGET_HWCINFO:
1630                 {
1631                         unsigned long *hwc_offset = (unsigned long *) arg;
1632
1633                         if (caps & HW_CURSOR_CAP)
1634                                 *hwc_offset = hwcursor_vbase -
1635                                     (unsigned long) ivideo.video_vbase;
1636                         else
1637                                 *hwc_offset = 0;
1638
1639                         break;
1640                 }
1641         case FBIOPUT_MODEINFO:
1642                 {    
1643                         struct mode_info *x = (struct mode_info *)arg;
1644
1645                         /* Set Mode Parameters by XServer */        
1646                         ivideo.video_bpp      = x->bpp;
1647                         ivideo.video_width    = x->xres;
1648                         ivideo.video_height   = x->yres;
1649                         ivideo.video_vwidth   = x->v_xres;
1650                         ivideo.video_vheight  = x->v_yres;
1651                         ivideo.org_x          = x->org_x;
1652                         ivideo.org_y          = x->org_y;
1653                         ivideo.refresh_rate   = x->vrate;
1654                         
1655                         break;
1656                 }
1657         case FBIOGET_DISPINFO:
1658                 sis_dispinfo((struct ap_data *)arg);
1659                 break;
1660         default:
1661                 return -EINVAL;
1662         }
1663         return 0;
1664 }
1665
1666 static int sisfb_mmap(struct fb_info *info, struct file *file,
1667                       struct vm_area_struct *vma)
1668 {
1669         struct fb_var_screeninfo var;
1670         unsigned long start;
1671         unsigned long off;
1672         u32 len;
1673
1674         if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1675                 return -EINVAL;
1676         off = vma->vm_pgoff << PAGE_SHIFT;
1677
1678         /* frame buffer memory */
1679         start = (unsigned long) ivideo.video_base;
1680         len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
1681
1682         if (off >= len) {
1683                 /* memory mapped io */
1684                 off -= len;
1685                 sisfb_get_var(&var, currcon, info);
1686                 if (var.accel_flags)
1687                         return -EINVAL;
1688                 start = (unsigned long) ivideo.mmio_base;
1689                 len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
1690         }
1691
1692         start &= PAGE_MASK;
1693         if ((vma->vm_end - vma->vm_start + off) > len)
1694                 return -EINVAL;
1695         off += start;
1696         vma->vm_pgoff = off >> PAGE_SHIFT;
1697
1698 #if defined(__i386__) || defined(__x86_64__)
1699         if (boot_cpu_data.x86 > 3)
1700                 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
1701 #endif
1702         if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
1703                                 vma->vm_page_prot)) 
1704                 return -EAGAIN;
1705         return 0;
1706 }
1707
1708 static struct fb_ops sisfb_ops = {
1709         owner:          THIS_MODULE,
1710         fb_get_fix:     sisfb_get_fix,
1711         fb_get_var:     sisfb_get_var,
1712         fb_set_var:     sisfb_set_var,
1713         fb_get_cmap:    sisfb_get_cmap,
1714         fb_set_cmap:    sisfb_set_cmap,
1715         fb_ioctl:       sisfb_ioctl,
1716         fb_mmap:        sisfb_mmap,
1717 };
1718
1719 int sisfb_setup(char *options)
1720 {
1721         char *this_opt;
1722
1723         fb_info.fontname[0] = '\0';
1724         ivideo.refresh_rate = 0;
1725
1726         if (!options || !*options)
1727                 return 0;
1728
1729         for (this_opt = strtok(options, ","); this_opt;
1730              this_opt = strtok(NULL, ",")) {
1731                 if (!*this_opt)
1732                         continue;
1733
1734                 if (!strcmp(this_opt, "inverse")) {
1735                         inverse = 1;
1736                         fb_invert_cmaps();
1737                 } else if (!strncmp(this_opt, "font:", 5)) {
1738                         strcpy(fb_info.fontname, this_opt + 5);
1739                 } else if (!strncmp(this_opt, "mode:", 5)) {
1740                         search_mode(this_opt + 5);
1741                 } else if (!strncmp(this_opt, "vrate:", 6)) {
1742                         ivideo.refresh_rate =
1743                             simple_strtoul(this_opt + 6, NULL, 0);
1744                 } else if (!strncmp(this_opt, "off", 3)) {
1745                         sisfb_off = 1;
1746                 } else if (!strncmp(this_opt, "crt1off", 7)) {
1747                         crt1off = 1;
1748                 } else
1749                         DPRINTK("invalid parameter %s\n", this_opt);
1750         }
1751         return 0;
1752 }
1753
1754 static int sisfb_update_var(int con, struct fb_info *info)
1755 {
1756         return 0;
1757 }
1758
1759 /*
1760  *    Switch Console (called by fbcon.c)
1761  */
1762
1763 static int sisfb_switch(int con, struct fb_info *info)
1764 {
1765         int cols, rows;
1766
1767         DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
1768
1769         /* update colormap of current console */
1770         if (fb_display[currcon].cmap.len)
1771                 fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
1772
1773         fb_display[con].var.activate = FB_ACTIVATE_NOW;
1774
1775         /* same mode, needn't change mode actually */
1776
1777         if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo))) 
1778         {
1779                 currcon = con;
1780                 return 1;
1781         }
1782
1783         currcon = con;
1784
1785         do_set_var(&fb_display[con].var, 1, info);
1786
1787         sisfb_set_disp(con, &fb_display[con].var);
1788
1789         /* Install new colormap */
1790         do_install_cmap(con, info);
1791
1792         cols = sisbios_mode[mode_idx].cols;
1793         rows = sisbios_mode[mode_idx].rows;
1794         vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1795
1796         sisfb_update_var(con, info);
1797
1798         return 1;
1799
1800 }
1801
1802 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1803
1804 static void sisfb_blank(int blank, struct fb_info *info)
1805 {
1806         u8 CRData;
1807
1808         vgawb(CRTC_ADR, 0x17);
1809         CRData = vgarb(CRTC_DATA);
1810
1811         if (blank > 0)          /* turn off CRT1 */
1812                 CRData &= 0x7f;
1813         else                    /* turn on CRT1 */
1814                 CRData |= 0x80;
1815
1816         vgawb(CRTC_ADR, 0x17);
1817         vgawb(CRTC_DATA, CRData);
1818 }
1819
1820 int has_VB(void)
1821 {
1822         u8 uSR38, uSR39, uVBChipID;
1823
1824         vgawb(SEQ_ADR, 0x38);
1825         uSR38 = vgarb(SEQ_DATA);
1826         vgawb(SEQ_ADR, 0x39);
1827         uSR39 = vgarb(SEQ_DATA);
1828         vgawb(IND_SIS_CRT2_PORT_14, 0x0);
1829         uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1);
1830
1831         if (
1832                 ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */
1833                 ||
1834                 ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */
1835                 ||
1836                 ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */
1837                 ||
1838                 ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */
1839            )
1840         {
1841                 ivideo.hasVB = HASVB_301;
1842                 return TRUE;
1843         }
1844         else
1845         {
1846                 ivideo.hasVB = HASVB_NONE;
1847                 return FALSE;
1848         }
1849 }
1850
1851 void sis_get301info(void)
1852 {
1853         u8 uCRData;
1854         unsigned long disp_state=0;
1855
1856         if (HwExt.jChipID >= SIS_Trojan)
1857         {
1858                 if (!has_VB())
1859                 {
1860                         vgawb(CRTC_ADR, 0x37);
1861                         uCRData = vgarb(CRTC_DATA);
1862
1863                         switch((uCRData >> 1) & 0x07)
1864                         {
1865                         case 2:
1866                                 ivideo.hasVB = HASVB_LVDS;
1867                                 break;
1868                         case 4:
1869                                 ivideo.hasVB = HASVB_LVDS_CHRONTEL;
1870                                 break;
1871                         case 3:
1872                                 ivideo.hasVB = HASVB_TRUMPION;
1873                                 break;
1874                         default:
1875                                 break;
1876                         }
1877                 }
1878         }
1879         else
1880         {
1881                 has_VB();
1882         }
1883
1884         vgawb(CRTC_ADR, 0x32);
1885         uCRData = vgarb(CRTC_DATA);
1886  
1887         switch(uDispType)
1888         {
1889         case MASK_DISPTYPE_CRT2: 
1890                 disp_state = DISPTYPE_CRT2;
1891                 break;
1892         case MASK_DISPTYPE_LCD:
1893                 disp_state = DISPTYPE_LCD;
1894                 break;
1895         case MASK_DISPTYPE_TV:
1896                 disp_state = DISPTYPE_TV;
1897                 break;
1898         }
1899
1900         if(disp_state & 0x7)
1901         {
1902                 if(crt1off)
1903                         disp_state |= DISPMODE_SINGLE;
1904                 else
1905                         disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
1906         }
1907         else
1908                 disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
1909
1910         ivideo.disp_state = disp_state;
1911 }
1912
1913
1914 int __init sisfb_init(void)
1915 {
1916         struct pci_dev *pdev = NULL;
1917         struct board *b;
1918         int pdev_valid = 0;
1919         unsigned char jTemp;
1920         u8 uSRData, uCRData;
1921
1922         outb(0x77, 0x80);
1923
1924         if (sisfb_off)
1925                 return -ENXIO;
1926
1927         pci_for_each_dev(pdev) {
1928                 for (b = dev_list; b->vendor; b++) 
1929                 {
1930                         if ((b->vendor == pdev->vendor)
1931                             && (b->device == pdev->device)) 
1932                         {
1933                                 pdev_valid = 1;
1934                                 strcpy(fb_info.modename, b->name);
1935                                 ivideo.chip_id = pdev->device;
1936                                 pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id);
1937                                 break;
1938                         }
1939                 }
1940
1941                 if (pdev_valid)
1942                         break;
1943         }
1944
1945         if (!pdev_valid)
1946                 return -1;
1947
1948         switch(ivideo.chip_id)
1949         {
1950         case PCI_DEVICE_ID_SI_300:
1951                 HwExt.jChipID = SIS_Glamour;
1952                 break;
1953         case PCI_DEVICE_ID_SI_630_VGA:
1954                 HwExt.jChipID = SIS_Trojan;
1955                 break;
1956         case PCI_DEVICE_ID_SI_540_VGA:
1957                 HwExt.jChipID = SIS_Spartan;
1958                 break;
1959         case PCI_DEVICE_ID_SI_730_VGA:
1960                 HwExt.jChipID = SIS_730;
1961                 break;
1962         }
1963
1964         ivideo.video_base = pci_resource_start(pdev, 0);
1965         ivideo.mmio_base = pci_resource_start(pdev, 1);
1966         ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30;
1967
1968         HwExt.IOAddress = (unsigned short)ivideo.vga_base; 
1969         rom_base = 0x000C0000;
1970
1971         MMIO_SIZE =  pci_resource_len(pdev, 1);
1972
1973 #ifdef NOBIOS
1974         if (pci_enable_device(pdev))
1975                 return -EIO;
1976         /* Image file instead of VGA-bios */
1977         HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData;
1978 #else
1979 #ifdef CONFIG_FB_SIS_LINUXBIOS
1980         if (pci_enable_device(pdev))
1981                 return -EIO;
1982         HwExt.VirtualRomBase = rom_vbase = 0;
1983 #else
1984         request_region(rom_base, 32, "sisfb");
1985         HwExt.VirtualRomBase = rom_vbase 
1986                 = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
1987 #endif
1988 #endif
1989         /* set passwd */
1990         vgawb(SEQ_ADR, IND_SIS_PASSWORD);
1991         vgawb(SEQ_DATA, SIS_PASSWORD);
1992
1993         /* Enable MMIO & PCI linear address */
1994         vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
1995         jTemp = vgarb(SEQ_DATA);
1996         jTemp |= SIS_PCI_ADDR_ENABLE;
1997         jTemp |= SIS_MEM_MAP_IO_ENABLE;
1998         vgawb(SEQ_DATA, jTemp);
1999
2000 #ifdef CONFIG_FB_SIS_LINUXBIOS
2001         pdev_valid = 0;
2002         pci_for_each_dev(pdev) {
2003                 u8 uPCIData=0;
2004
2005                 if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630)) 
2006                 {
2007                         pci_read_config_byte(pdev, 0x63, &uPCIData);
2008                         uPCIData = (uPCIData & 0x70) >> 4;
2009                         ivideo.video_size = (unsigned int)(1 << (uPCIData+21));
2010                         pdev_valid = 1;
2011                         break;
2012                 }
2013         }
2014
2015         if (!pdev_valid)
2016                 return -1;
2017 #else
2018         vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
2019         ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
2020 #endif
2021
2022
2023         /* get CRT2 connection state */
2024         vgawb(SEQ_ADR, 0x17);
2025         uSRData = vgarb(SEQ_DATA);
2026         vgawb(CRTC_ADR, 0x32);
2027         uCRData = vgarb(CRTC_DATA);
2028
2029         ivideo.TV_plug = ivideo.TV_type = 0;
2030         if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan))
2031         {
2032                 /* CRT1 connect detection */
2033                 if((uSRData & 0x01) && !crt1off)
2034                         crt1off = 0;
2035                 else
2036                 {
2037                         if(uSRData&0x0E)     /* DISP2 connected */
2038                                 crt1off = 1;
2039                         else
2040                                 crt1off = 0;
2041                 }
2042
2043                 /* detection priority : CRT2 > LCD > TV */
2044                 if(uSRData & 0x08 )
2045                         uDispType = MASK_DISPTYPE_CRT2;
2046                 else if(uSRData & 0x02)
2047                         uDispType = MASK_DISPTYPE_LCD;
2048                 else if(uSRData & 0x04)
2049                 {
2050                         if(uSRData & 0x80)
2051                         {
2052                                 ivideo.TV_type = TVMODE_HIVISION;
2053                                 ivideo.TV_plug = TVPLUG_SVIDEO;
2054                         }
2055                         else if(uSRData & 0x20)
2056                                 ivideo.TV_plug = TVPLUG_SVIDEO;
2057                         else if(uSRData & 0x10)
2058                                 ivideo.TV_plug = TVPLUG_COMPOSITE;
2059                         else if(uSRData & 0x40)
2060                                 ivideo.TV_plug = TVPLUG_SCART;
2061
2062                         if(ivideo.TV_type == 0)
2063                         {
2064                                 u8 uSR16;
2065                                 vgawb(SEQ_ADR, 0x16);
2066                                 uSR16 = vgarb(SEQ_DATA);
2067                                 if(uSR16 & 0x20)
2068                                         ivideo.TV_type = TVMODE_PAL;
2069                                 else
2070                                         ivideo.TV_type = TVMODE_NTSC;
2071                         }
2072
2073                         uDispType = MASK_DISPTYPE_TV;
2074                 }
2075         } 
2076         else
2077         {
2078                 if((uCRData & 0x20) && !crt1off)
2079                         crt1off = 0;
2080                 else
2081                 {
2082                         if(uCRData&0x5F)   /* DISP2 connected */
2083                                 crt1off = 1;
2084                         else
2085                                 crt1off = 0;
2086                 }
2087
2088                 if(uCRData & 0x10)
2089                         uDispType = MASK_DISPTYPE_CRT2;
2090                 else if(uCRData & 0x08)
2091                         uDispType = MASK_DISPTYPE_LCD;
2092                 else if(uCRData & 0x47)
2093                 {
2094                         uDispType = MASK_DISPTYPE_TV;
2095
2096                         if(uCRData & 0x40)
2097                         {
2098                                 ivideo.TV_type = TVMODE_HIVISION;
2099                                 ivideo.TV_plug = TVPLUG_SVIDEO;
2100                         }
2101                         else if(uCRData & 0x02)
2102                                 ivideo.TV_plug = TVPLUG_SVIDEO;
2103                         else if(uCRData & 0x01)
2104                                 ivideo.TV_plug = TVPLUG_COMPOSITE;
2105                         else if(uCRData & 0x04)
2106                                 ivideo.TV_plug = TVPLUG_SCART;
2107
2108                         if(ivideo.TV_type == 0)
2109                         {
2110                                 u8 uTemp;
2111                                 uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52));
2112                                 if(uTemp&0x40)
2113                                 {
2114                                         uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53));
2115                                 }
2116                                 else
2117                                 {
2118                                         vgawb(SEQ_ADR, 0x38);
2119                                         uTemp = vgarb(SEQ_DATA);
2120                                 }
2121                                 if(uTemp & 0x01)
2122                                         ivideo.TV_type = TVMODE_PAL;
2123                                 else
2124                                         ivideo.TV_type = TVMODE_NTSC;
2125                         }
2126                 }
2127         }
2128
2129         if(uDispType == MASK_DISPTYPE_LCD)   // LCD conntected
2130         {
2131                 // TODO: set LCDType by EDID
2132                 HwExt.usLCDType = LCD1024;
2133         }
2134
2135         if (HwExt.jChipID >= SIS_Trojan)
2136         {
2137                 vgawb(SEQ_ADR, 0x1A);
2138                 uSRData = vgarb(SEQ_DATA);
2139                 if (uSRData & 0x10)
2140                         HwExt.bIntegratedMMEnabled = TRUE;
2141                 else
2142                         HwExt.bIntegratedMMEnabled = FALSE;
2143         }
2144
2145         if(mode_idx >= 0)       /* mode found */
2146         {
2147                 /* Filtering mode for VB */
2148                 switch(uDispType & MASK_DISPTYPE_DISP2)
2149                 {
2150                 case MASK_DISPTYPE_LCD:
2151                         switch(HwExt.usLCDType)
2152                         {
2153                 case LCD1024:
2154                                 if(sisbios_mode[mode_idx].xres > 1024)
2155                                         mode_idx = -1;
2156                                 break;
2157                 case LCD1280:
2158                                 if(sisbios_mode[mode_idx].xres > 1280)
2159                                         mode_idx = -1;
2160                                 break;
2161                 case LCD2048:
2162                                 if(sisbios_mode[mode_idx].xres > 2048)
2163                                         mode_idx = -1;
2164                                 break;
2165                 case LCD1920:
2166                                 if(sisbios_mode[mode_idx].xres > 1920)
2167                                         mode_idx = -1;
2168                                 break;
2169                 case LCD1600:
2170                                 if(sisbios_mode[mode_idx].xres > 1600)
2171                                         mode_idx = -1;
2172                                 break;
2173                 case LCD800:
2174                                 if(sisbios_mode[mode_idx].xres > 800)
2175                                         mode_idx = -1;
2176                                 break;
2177                 case LCD640:
2178                                 if(sisbios_mode[mode_idx].xres > 640)
2179                                         mode_idx = -1;
2180                                 break;
2181                         default:
2182                                 mode_idx = -1;
2183                         }
2184
2185                         if(sisbios_mode[mode_idx].xres == 720)  /* only for TV */
2186                                 mode_idx = -1;
2187                         break;
2188                 case MASK_DISPTYPE_TV:
2189                         switch(sisbios_mode[mode_idx].xres)
2190                         {
2191                         case 800:
2192                         case 640:
2193                                 break;
2194                         case 720:
2195                                 if(ivideo.TV_type == TVMODE_NTSC)
2196                                 {
2197                                         if(sisbios_mode[mode_idx].yres != 480)
2198                                                 mode_idx = -1;
2199                                 }
2200                                 else if(ivideo.TV_type == TVMODE_PAL)
2201                                 {
2202                                         if(sisbios_mode[mode_idx].yres != 576)
2203                                                 mode_idx = -1;
2204                                 }
2205                                 break;
2206                         default:
2207                                 /* illegal mode */
2208                                 mode_idx = -1;
2209                         }
2210                         break;
2211                 }
2212         }       
2213         
2214         if (mode_idx < 0)
2215         {
2216                 switch(uDispType & MASK_DISPTYPE_DISP2)
2217                 {
2218                 case MASK_DISPTYPE_LCD:
2219                         mode_idx = DEFAULT_LCDMODE;
2220                         break;
2221                 case MASK_DISPTYPE_TV:
2222                         mode_idx = DEFAULT_TVMODE;
2223                         break;
2224                 default:
2225                         mode_idx = DEFAULT_MODE;
2226                 }
2227         }
2228
2229 #ifdef CONFIG_FB_SIS_LINUXBIOS
2230         mode_idx = DEFAULT_MODE;
2231         rate_idx = sisbios_mode[mode_idx].rate_idx;
2232         /* set to default refresh rate 60MHz */
2233         ivideo.refresh_rate = 60;
2234 #endif
2235
2236         mode_no = sisbios_mode[mode_idx].mode_no;
2237
2238         if (ivideo.refresh_rate != 0)
2239                 search_refresh_rate(ivideo.refresh_rate);
2240
2241         if (rate_idx == 0) {
2242                 rate_idx = sisbios_mode[mode_idx].rate_idx;     
2243                 /* set to default refresh rate 60MHz */
2244                 ivideo.refresh_rate = 60;
2245         }
2246
2247         ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
2248         ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
2249         ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
2250         ivideo.org_x = ivideo.org_y = 0;
2251         video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
2252
2253         printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n", 
2254                 ivideo.video_base, (unsigned int)ivideo.video_size/1024);
2255         printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n", 
2256                 ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024);
2257
2258
2259         if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) 
2260         {
2261                 printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
2262                 return -ENODEV;
2263         }
2264
2265         if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO")) 
2266         {
2267                 printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
2268                 release_mem_region(ivideo.video_base, ivideo.video_size);
2269                 return -ENODEV;
2270         }
2271
2272         HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase 
2273                 = ioremap(ivideo.video_base, ivideo.video_size);
2274         ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
2275
2276 #ifdef NOBIOS
2277         SiSInit300(&HwExt);
2278 #else
2279 #ifdef CONFIG_FB_SIS_LINUXBIOS
2280         SiSInit300(&HwExt);
2281 #endif
2282 #endif
2283         printk(KERN_INFO
2284                "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
2285                ivideo.video_base, ivideo.video_vbase,
2286                ivideo.video_size / 1024);
2287         printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
2288                ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
2289                video_linelength);
2290
2291         /* enable 2D engine */
2292         vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
2293         jTemp = vgarb(SEQ_DATA);
2294         jTemp |= SIS_2D_ENABLE;
2295         vgawb(SEQ_DATA, jTemp);
2296
2297         pre_setmode();
2298
2299         if (SiSSetMode(&HwExt, mode_no)) {
2300                 DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no);
2301                 return -1;
2302         }
2303
2304         post_setmode();
2305
2306         /* Get VB functions */
2307         sis_get301info();
2308
2309         crtc_to_var(&default_var);
2310
2311         fb_info.changevar = NULL;
2312         fb_info.node = -1;
2313         fb_info.fbops = &sisfb_ops;
2314         fb_info.disp = &disp;
2315         fb_info.switch_con = &sisfb_switch;
2316         fb_info.updatevar = &sisfb_update_var;
2317         fb_info.blank = &sisfb_blank;
2318         fb_info.flags = FBINFO_FLAG_DEFAULT;
2319
2320         sisfb_set_disp(-1, &default_var);
2321
2322         if (sisfb_heap_init()) {
2323                 DPRINTK("sisfb: Failed to enable offscreen heap\n");
2324         }
2325
2326         /* to avoid the inversed bgcolor bug of the initial state */
2327         vc_resize_con(1, 1, 0);
2328
2329         if (register_framebuffer(&fb_info) < 0)
2330                 return -EINVAL;
2331
2332         printk(KERN_INFO "fb%d: %s frame buffer device\n",
2333                GET_FB_IDX(fb_info.node), fb_info.modename);
2334
2335         return 0;
2336 }
2337
2338 #ifdef MODULE
2339
2340 static char *mode = NULL;
2341 static unsigned int rate = 0;
2342 static unsigned int crt1 = 1;
2343
2344 MODULE_PARM(mode, "s");
2345 MODULE_PARM(rate, "i");
2346 MODULE_PARM(crt1, "i"); /* default: CRT1 enable */
2347
2348 int init_module(void)
2349 {
2350         if (mode)
2351                 search_mode(mode);
2352
2353         ivideo.refresh_rate = rate;
2354
2355         if(crt1 == 0)
2356                 crt1off = 1;
2357         else
2358                 crt1off = 0;
2359         
2360         sisfb_init();
2361
2362         return 0;
2363 }
2364
2365 void cleanup_module(void)
2366 {
2367         unregister_framebuffer(&fb_info);
2368 }
2369 #endif                          /* MODULE */
2370
2371
2372 EXPORT_SYMBOL(sis_malloc);
2373 EXPORT_SYMBOL(sis_free);
2374
2375 EXPORT_SYMBOL(ivideo);