vserver 2.0 rc7
[linux-2.6.git] / drivers / video / sis / sis_main.c
1 /*
2  * SiS 300/305/540/630(S)/730(S)
3  * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
4  * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
5  *
6  * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the named License,
11  * or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21  *
22  * Author:      Thomas Winischhofer <thomas@winischhofer.net>
23  *
24  * Author of (practically wiped) code base:
25  *              SiS (www.sis.com)
26  *              Copyright (C) 1999 Silicon Integrated Systems, Inc.
27  *
28  * See http://www.winischhofer.net/ for more information and updates
29  *
30  * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
31  * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
32  *
33  */
34
35 #include <linux/config.h>
36 #include <linux/version.h>
37 #include <linux/module.h>
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39 #include <linux/moduleparam.h>
40 #endif
41 #include <linux/kernel.h>
42 #include <linux/smp_lock.h>
43 #include <linux/spinlock.h>
44 #include <linux/errno.h>
45 #include <linux/string.h>
46 #include <linux/mm.h>
47 #include <linux/tty.h>
48 #include <linux/slab.h>
49 #include <linux/delay.h>
50 #include <linux/fb.h>
51 #include <linux/console.h>
52 #include <linux/selection.h>
53 #include <linux/smp_lock.h>
54 #include <linux/ioport.h>
55 #include <linux/init.h>
56 #include <linux/pci.h>
57 #include <linux/vmalloc.h>
58 #include <linux/vt_kern.h>
59 #include <linux/capability.h>
60 #include <linux/fs.h>
61 #include <linux/types.h>
62 #include <asm/uaccess.h>
63 #include <asm/io.h>
64 #ifdef CONFIG_MTRR
65 #include <asm/mtrr.h>
66 #endif
67
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69 #include <video/fbcon.h>
70 #include <video/fbcon-cfb8.h>
71 #include <video/fbcon-cfb16.h>
72 #include <video/fbcon-cfb24.h>
73 #include <video/fbcon-cfb32.h>
74 #endif
75
76 #include "sis.h"
77 #include "sis_main.h"
78
79 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81 #error "This version of sisfb requires at least 2.6.3"
82 #endif
83 #endif
84
85 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86 #ifdef FBCON_HAS_CFB8
87 extern struct display_switch fbcon_sis8;
88 #endif
89 #ifdef FBCON_HAS_CFB16
90 extern struct display_switch fbcon_sis16;
91 #endif
92 #ifdef FBCON_HAS_CFB32
93 extern struct display_switch fbcon_sis32;
94 #endif
95 #endif
96
97 /* ------------------ Internal helper routines ----------------- */
98
99 static void __init
100 sisfb_setdefaultparms(void)
101 {
102         sisfb_off               = 0;
103         sisfb_parm_mem          = 0;
104         sisfb_accel             = -1;
105         sisfb_ypan              = -1;
106         sisfb_max               = -1;
107         sisfb_userom            = -1;
108         sisfb_useoem            = -1;
109 #ifdef MODULE
110         /* Module: "None" for 2.4, default mode for 2.5+ */
111 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
112         sisfb_mode_idx          = -1;
113 #else
114         sisfb_mode_idx          = MODE_INDEX_NONE;
115 #endif
116 #else
117         /* Static: Default mode */
118         sisfb_mode_idx          = -1;
119 #endif
120         sisfb_parm_rate         = -1;
121         sisfb_crt1off           = 0;
122         sisfb_forcecrt1         = -1;
123         sisfb_crt2type          = -1;
124         sisfb_crt2flags         = 0;
125         sisfb_pdc               = 0xff;
126         sisfb_pdca              = 0xff;
127         sisfb_scalelcd          = -1;
128         sisfb_specialtiming     = CUT_NONE;
129         sisfb_lvdshl            = -1;
130         sisfb_dstn              = 0;
131         sisfb_fstn              = 0;
132         sisfb_tvplug            = -1;
133         sisfb_tvstd             = -1;
134         sisfb_tvxposoffset      = 0;
135         sisfb_tvyposoffset      = 0;
136         sisfb_filter            = -1;
137         sisfb_nocrt2rate        = 0;
138 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
139         sisfb_inverse           = 0;
140         sisfb_fontname[0]       = 0;
141 #endif
142 #if !defined(__i386__) && !defined(__x86_64__)
143         sisfb_resetcard         = 0;
144         sisfb_videoram          = 0;
145 #endif
146 }
147
148 static void __devinit
149 sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
150 {
151         int i = 0, j = 0;
152
153         /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
154
155         if(vesamode == 0) {
156 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
157                 sisfb_mode_idx = MODE_INDEX_NONE;
158 #else
159                 if(!quiet) {
160                    printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
161                 }
162                 sisfb_mode_idx = DEFAULT_MODE;
163 #endif
164                 return;
165         }
166
167         vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
168
169         while(sisbios_mode[i++].mode_no[0] != 0) {
170                 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
171                     (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
172                     if(sisfb_fstn) {
173                        if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
174                           sisbios_mode[i-1].mode_no[1] == 0x56 ||
175                           sisbios_mode[i-1].mode_no[1] == 0x53) continue;
176                     } else {
177                        if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
178                           sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
179                     }
180                     sisfb_mode_idx = i - 1;
181                     j = 1;
182                     break;
183                 }
184         }
185         if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
186 }
187
188 static void
189 sisfb_search_mode(char *name, BOOLEAN quiet)
190 {
191         int i = 0;
192         unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
193         char strbuf[16], strbuf1[20];
194         char *nameptr = name;
195
196         /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
197
198         if(name == NULL) {
199            if(!quiet) {
200               printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
201            }
202            sisfb_mode_idx = DEFAULT_MODE;
203            return;
204         }
205
206 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
207         if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
208            if(!quiet) {
209               printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
210            }
211            sisfb_mode_idx = DEFAULT_MODE;
212            return;
213         }
214 #endif
215         if(strlen(name) <= 19) {
216            strcpy(strbuf1, name);
217            for(i=0; i<strlen(strbuf1); i++) {
218               if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
219            }
220
221            /* This does some fuzzy mode naming detection */
222            if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
223               if((rate <= 32) || (depth > 32)) {
224                  j = rate; rate = depth; depth = j;
225               }
226               sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
227               nameptr = strbuf;
228               sisfb_parm_rate = rate;
229            } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
230               sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
231               nameptr = strbuf;
232            } else {
233               xres = 0;
234               if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
235                  sprintf(strbuf, "%ux%ux8", xres, yres);
236                  nameptr = strbuf;
237               } else {
238                  sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
239                  return;
240               }
241            }
242         }
243
244         i = 0; j = 0;
245         while(sisbios_mode[i].mode_no[0] != 0) {
246                 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
247                         if(sisfb_fstn) {
248                                 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
249                                    sisbios_mode[i-1].mode_no[1] == 0x56 ||
250                                    sisbios_mode[i-1].mode_no[1] == 0x53) continue;
251                         } else {
252                                 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
253                                    sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
254                         }
255                         sisfb_mode_idx = i - 1;
256                         j = 1;
257                         break;
258                 }
259         }
260         if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
261 }
262
263 #ifndef MODULE
264 static void __devinit
265 sisfb_get_vga_mode_from_kernel(void)
266 {
267 #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
268         char mymode[32];
269         int  mydepth = screen_info.lfb_depth;
270
271         if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
272
273         if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
274             (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
275             (mydepth >= 8) && (mydepth <= 32) ) {
276
277             if(mydepth == 24) mydepth = 32;
278
279             sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
280                                         screen_info.lfb_height,
281                                         mydepth);
282
283             printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
284
285             sisfb_search_mode(mymode, TRUE);
286         }
287 #endif
288         return;
289 }
290 #endif
291
292 static void __init
293 sisfb_search_crt2type(const char *name)
294 {
295         int i = 0;
296
297         /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
298
299         if(name == NULL) return;
300
301         while(sis_crt2type[i].type_no != -1) {
302                 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
303                         sisfb_crt2type = sis_crt2type[i].type_no;
304                         sisfb_tvplug = sis_crt2type[i].tvplug_no;
305                         sisfb_crt2flags = sis_crt2type[i].flags;
306                         break;
307                 }
308                 i++;
309         }
310
311         sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
312         sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
313
314         if(sisfb_crt2type < 0) {
315                 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
316         }
317 }
318
319 static void __init
320 sisfb_search_tvstd(const char *name)
321 {
322         int i = 0;
323
324         /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
325
326         if(name == NULL) return;
327
328         while(sis_tvtype[i].type_no != -1) {
329                 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
330                         sisfb_tvstd = sis_tvtype[i].type_no;
331                         break;
332                 }
333                 i++;
334         }
335 }
336
337 static void __init
338 sisfb_search_specialtiming(const char *name)
339 {
340         int i = 0;
341         BOOLEAN found = FALSE;
342
343         /* BEWARE: We don't know the hardware specs yet and there is no ivideo */
344
345         if(name == NULL) return;
346
347         if(!strnicmp(name, "none", 4)) {
348                 sisfb_specialtiming = CUT_FORCENONE;
349                 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
350         } else {
351            while(mycustomttable[i].chipID != 0) {
352               if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
353                  sisfb_specialtiming = mycustomttable[i].SpecialID;
354                  found = TRUE;
355                  printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
356                         mycustomttable[i].vendorName, mycustomttable[i].cardName,
357                         mycustomttable[i].optionName);
358                  break;
359               }
360               i++;
361            }
362            if(!found) {
363               printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
364               printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
365               i = 0;
366               while(mycustomttable[i].chipID != 0) {
367                  printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
368                      mycustomttable[i].optionName,
369                      mycustomttable[i].vendorName,
370                      mycustomttable[i].cardName);
371                  i++;
372               }
373            }
374         }
375 }
376
377 static BOOLEAN __devinit
378 sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
379 {
380         int i, j, xres, yres, refresh, index;
381         u32 emodes;
382
383         if(buffer[0] != 0x00 || buffer[1] != 0xff ||
384            buffer[2] != 0xff || buffer[3] != 0xff ||
385            buffer[4] != 0xff || buffer[5] != 0xff ||
386            buffer[6] != 0xff || buffer[7] != 0x00) {
387            printk(KERN_DEBUG "sisfb: Bad EDID header\n");
388            return FALSE;
389         }
390
391         if(buffer[0x12] != 0x01) {
392            printk(KERN_INFO "sisfb: EDID version %d not supported\n",
393                 buffer[0x12]);
394            return FALSE;
395         }
396
397         monitor->feature = buffer[0x18];
398
399         if(!buffer[0x14] & 0x80) {
400            if(!(buffer[0x14] & 0x08)) {
401               printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");
402            }
403         }
404
405         if(buffer[0x13] >= 0x01) {
406            /* EDID V1 rev 1 and 2: Search for monitor descriptor
407             * to extract ranges
408             */
409             j = 0x36;
410             for(i=0; i<4; i++) {
411                if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
412                   buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
413                   buffer[j + 4] == 0x00) {
414                   monitor->hmin = buffer[j + 7];
415                   monitor->hmax = buffer[j + 8];
416                   monitor->vmin = buffer[j + 5];
417                   monitor->vmax = buffer[j + 6];
418                   monitor->dclockmax = buffer[j + 9] * 10 * 1000;
419                   monitor->datavalid = TRUE;
420                   break;
421                }
422                j += 18;
423             }
424         }
425
426         if(!monitor->datavalid) {
427            /* Otherwise: Get a range from the list of supported
428             * Estabished Timings. This is not entirely accurate,
429             * because fixed frequency monitors are not supported
430             * that way.
431             */
432            monitor->hmin = 65535; monitor->hmax = 0;
433            monitor->vmin = 65535; monitor->vmax = 0;
434            monitor->dclockmax = 0;
435            emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
436            for(i = 0; i < 13; i++) {
437               if(emodes & sisfb_ddcsmodes[i].mask) {
438                  if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
439                  if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
440                  if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
441                  if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
442                  if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
443               }
444            }
445            index = 0x26;
446            for(i = 0; i < 8; i++) {
447               xres = (buffer[index] + 31) * 8;
448               switch(buffer[index + 1] & 0xc0) {
449                  case 0xc0: yres = (xres * 9) / 16; break;
450                  case 0x80: yres = (xres * 4) /  5; break;
451                  case 0x40: yres = (xres * 3) /  4; break;
452                  default:   yres = xres;            break;
453               }
454               refresh = (buffer[index + 1] & 0x3f) + 60;
455               if((xres >= 640) && (yres >= 480)) {
456                  for(j = 0; j < 8; j++) {
457                     if((xres == sisfb_ddcfmodes[j].x) &&
458                        (yres == sisfb_ddcfmodes[j].y) &&
459                        (refresh == sisfb_ddcfmodes[j].v)) {
460                       if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
461                       if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
462                       if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
463                       if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
464                       if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
465                     }
466                  }
467               }
468               index += 2;
469            }
470            if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
471               monitor->datavalid = TRUE;
472            }
473         }
474
475         return(monitor->datavalid);
476 }
477
478 static void __devinit
479 sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
480 {
481         USHORT  temp, i, realcrtno = crtno;
482         u8      buffer[256];
483
484         monitor->datavalid = FALSE;
485
486         if(crtno) {
487            if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
488            else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
489            else return;
490         }
491
492         if((ivideo->sisfb_crt1off) && (!crtno)) return;
493
494         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
495                                 realcrtno, 0, &buffer[0]);
496         if((!temp) || (temp == 0xffff)) {
497            printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
498            return;
499         } else {
500            printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
501            printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
502                 crtno + 1,
503                 (temp & 0x1a) ? "" : "[none of the supported]",
504                 (temp & 0x02) ? "2 " : "",
505                 (temp & 0x08) ? "D&P" : "",
506                 (temp & 0x10) ? "FPDI-2" : "");
507            if(temp & 0x02) {
508               i = 3;  /* Number of retrys */
509               do {
510                  temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
511                                      realcrtno, 1, &buffer[0]);
512               } while((temp) && i--);
513               if(!temp) {
514                  if(sisfb_interpret_edid(monitor, &buffer[0])) {
515                     printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
516                         monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
517                         monitor->dclockmax / 1000);
518                  } else {
519                     printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
520                  }
521               } else {
522                  printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
523               }
524            } else {
525               printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
526            }
527         }
528 }
529
530 static BOOLEAN
531 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
532                 int mode_idx, int rate_idx, int rate)
533 {
534         int htotal, vtotal;
535         unsigned int dclock, hsync;
536
537         if(!monitor->datavalid) return TRUE;
538
539         if(mode_idx < 0) return FALSE;
540
541         /* Skip for 320x200, 320x240, 640x400 */
542         switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
543         case 0x59:
544         case 0x41:
545         case 0x4f:
546         case 0x50:
547         case 0x56:
548         case 0x53:
549         case 0x2f:
550         case 0x5d:
551         case 0x5e:
552                 return TRUE;
553 #ifdef CONFIG_FB_SIS_315
554         case 0x5a:
555         case 0x5b:
556                 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
557 #endif
558         }
559
560         if(rate < (monitor->vmin - 1)) return FALSE;
561         if(rate > (monitor->vmax + 1)) return FALSE;
562
563         if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
564                                   sisbios_mode[mode_idx].mode_no[ivideo->mni],
565                                   &htotal, &vtotal, rate_idx)) {
566                 dclock = (htotal * vtotal * rate) / 1000;
567                 if(dclock > (monitor->dclockmax + 1000)) return FALSE;
568                 hsync = dclock / htotal;
569                 if(hsync < (monitor->hmin - 1)) return FALSE;
570                 if(hsync > (monitor->hmax + 1)) return FALSE;
571         } else {
572                 return FALSE;
573         }
574         return TRUE;
575 }
576
577 static int
578 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
579 {
580    u16 xres=0, yres, myres;
581
582 #ifdef CONFIG_FB_SIS_300
583    if(ivideo->sisvga_engine == SIS_300_VGA) {
584       if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
585    }
586 #endif
587 #ifdef CONFIG_FB_SIS_315
588    if(ivideo->sisvga_engine == SIS_315_VGA) {
589       if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
590    }
591 #endif
592
593    myres = sisbios_mode[myindex].yres;
594
595    switch(vbflags & VB_DISPTYPE_DISP2) {
596
597      case CRT2_LCD:
598
599         xres = ivideo->lcdxres; yres = ivideo->lcdyres;
600
601         if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
602                 if(sisbios_mode[myindex].xres > xres) return(-1);
603                 if(myres > yres) return(-1);
604         }
605
606         if(vbflags & (VB_LVDS | VB_30xBDH)) {
607            if(sisbios_mode[myindex].xres == 320) {
608               if((myres == 240) || (myres == 480)) {
609                  if(!ivideo->sisfb_fstn) {
610                     if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
611                        sisbios_mode[myindex].mode_no[1] == 0x5b)
612                        return(-1);
613                  } else {
614                     if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
615                        sisbios_mode[myindex].mode_no[1] == 0x56 ||
616                        sisbios_mode[myindex].mode_no[1] == 0x53)
617                        return(-1);
618                  }
619               }
620            }
621         }
622
623         if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
624                              sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
625                              ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
626                 return(-1);
627         }
628         break;
629
630      case CRT2_TV:
631         if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
632                             sisbios_mode[myindex].yres, 0) < 0x14) {
633                 return(-1);
634         }
635         break;
636
637      case CRT2_VGA:
638         if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
639                               sisbios_mode[myindex].yres, 0) < 0x14) {
640                 return(-1);
641         }
642         break;
643      }
644
645      return(myindex);
646 }
647
648 static u8
649 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
650 {
651         u16 xres, yres;
652         int i = 0;
653
654         xres = sisbios_mode[mode_idx].xres;
655         yres = sisbios_mode[mode_idx].yres;
656
657         ivideo->rate_idx = 0;
658         while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
659                 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
660                         if(sisfb_vrate[i].refresh == rate) {
661                                 ivideo->rate_idx = sisfb_vrate[i].idx;
662                                 break;
663                         } else if(sisfb_vrate[i].refresh > rate) {
664                                 if((sisfb_vrate[i].refresh - rate) <= 3) {
665                                         DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
666                                                 rate, sisfb_vrate[i].refresh);
667                                         ivideo->rate_idx = sisfb_vrate[i].idx;
668                                         ivideo->refresh_rate = sisfb_vrate[i].refresh;
669                                 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
670                                                 && (sisfb_vrate[i].idx != 1)) {
671                                         DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
672                                                 rate, sisfb_vrate[i-1].refresh);
673                                         ivideo->rate_idx = sisfb_vrate[i-1].idx;
674                                         ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
675                                 } 
676                                 break;
677                         } else if((rate - sisfb_vrate[i].refresh) <= 2) {
678                                 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
679                                                 rate, sisfb_vrate[i].refresh);
680                                 ivideo->rate_idx = sisfb_vrate[i].idx;
681                                 break;
682                         }
683                 }
684                 i++;
685         }
686         if(ivideo->rate_idx > 0) {
687                 return ivideo->rate_idx;
688         } else {
689                 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
690                                 rate, xres, yres);
691                 return 0;
692         }
693 }
694
695 static BOOLEAN
696 sisfb_bridgeisslave(struct sis_video_info *ivideo)
697 {
698    unsigned char P1_00;
699
700    if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
701
702    inSISIDXREG(SISPART1,0x00,P1_00);
703    if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
704        ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
705            return TRUE;
706    } else {
707            return FALSE;
708    }
709 }
710
711 static BOOLEAN
712 sisfballowretracecrt1(struct sis_video_info *ivideo)
713 {
714    u8 temp;
715
716    inSISIDXREG(SISCR,0x17,temp);
717    if(!(temp & 0x80)) return FALSE;
718
719    inSISIDXREG(SISSR,0x1f,temp);
720    if(temp & 0xc0) return FALSE;
721
722    return TRUE;
723 }
724
725 static BOOLEAN
726 sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
727 {
728    if(!sisfballowretracecrt1(ivideo)) return FALSE;
729
730    if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
731    else                            return FALSE;
732 }
733
734 static void
735 sisfbwaitretracecrt1(struct sis_video_info *ivideo)
736 {
737    int watchdog;
738
739    if(!sisfballowretracecrt1(ivideo)) return;
740
741    watchdog = 65536;
742    while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
743    watchdog = 65536;
744    while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
745 }
746
747 static BOOLEAN
748 sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
749 {
750    unsigned char temp, reg;
751
752    switch(ivideo->sisvga_engine) {
753    case SIS_300_VGA: reg = 0x25; break;
754    case SIS_315_VGA: reg = 0x30; break;
755    default:          return FALSE;
756    }
757
758    inSISIDXREG(SISPART1, reg, temp);
759    if(temp & 0x02) return TRUE;
760    else            return FALSE;
761 }
762
763 static BOOLEAN
764 sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
765 {
766    if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
767       if(sisfb_bridgeisslave(ivideo)) {
768          return(sisfbcheckvretracecrt1(ivideo));
769       } else {
770          return(sisfbcheckvretracecrt2(ivideo));
771       }
772    } 
773    return(sisfbcheckvretracecrt1(ivideo));
774 }
775
776 static u32
777 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
778 {
779    u8 idx, reg1, reg2, reg3, reg4;
780    u32 ret = 0;
781
782    (*vcount) = (*hcount) = 0;
783
784    if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
785       ret |= (FB_VBLANK_HAVE_VSYNC  |
786               FB_VBLANK_HAVE_HBLANK |
787               FB_VBLANK_HAVE_VBLANK |
788               FB_VBLANK_HAVE_VCOUNT |
789               FB_VBLANK_HAVE_HCOUNT);
790       switch(ivideo->sisvga_engine) {
791          case SIS_300_VGA: idx = 0x25; break;
792          default:
793          case SIS_315_VGA: idx = 0x30; break;
794       }
795       inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
796       inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
797       inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
798       inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
799       if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
800       if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
801       if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
802       (*vcount) = reg3 | ((reg4 & 0x70) << 4);
803       (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
804    } else if(sisfballowretracecrt1(ivideo)) {
805       ret |= (FB_VBLANK_HAVE_VSYNC  |
806               FB_VBLANK_HAVE_VBLANK |
807               FB_VBLANK_HAVE_VCOUNT |
808               FB_VBLANK_HAVE_HCOUNT);
809       reg1 = inSISREG(SISINPSTAT);
810       if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
811       if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
812       inSISIDXREG(SISCR,0x20,reg1);
813       inSISIDXREG(SISCR,0x1b,reg1);
814       inSISIDXREG(SISCR,0x1c,reg2);
815       inSISIDXREG(SISCR,0x1d,reg3);
816       (*vcount) = reg2 | ((reg3 & 0x07) << 8);
817       (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
818    }
819    return ret;
820 }
821
822 static int
823 sisfb_myblank(struct sis_video_info *ivideo, int blank)
824 {
825    u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
826    BOOLEAN backlight = TRUE;
827
828    switch(blank) {
829    case FB_BLANK_UNBLANK:       /* on */
830       sr01  = 0x00;
831       sr11  = 0x00;
832       sr1f  = 0x00;
833       cr63  = 0x00;
834       p2_0  = 0x20;
835       p1_13 = 0x00;
836       backlight = TRUE;
837       break;
838    case FB_BLANK_NORMAL:        /* blank */
839       sr01  = 0x20;
840       sr11  = 0x00;
841       sr1f  = 0x00;
842       cr63  = 0x00;
843       p2_0  = 0x20;
844       p1_13 = 0x00;
845       backlight = TRUE;
846       break;
847    case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
848       sr01  = 0x20;
849       sr11  = 0x08;
850       sr1f  = 0x80;
851       cr63  = 0x40;
852       p2_0  = 0x40;
853       p1_13 = 0x80;
854       backlight = FALSE;
855       break;
856    case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
857       sr01  = 0x20;
858       sr11  = 0x08;
859       sr1f  = 0x40;
860       cr63  = 0x40;
861       p2_0  = 0x80;
862       p1_13 = 0x40;
863       backlight = FALSE;
864       break;
865    case FB_BLANK_POWERDOWN:     /* off */
866       sr01  = 0x20;
867       sr11  = 0x08;
868       sr1f  = 0xc0;
869       cr63  = 0x40;
870       p2_0  = 0xc0;
871       p1_13 = 0xc0;
872       backlight = FALSE;
873       break;
874    default:
875       return 1;
876    }
877
878    if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
879
880       if( (!ivideo->sisfb_thismonitor.datavalid) ||
881           ((ivideo->sisfb_thismonitor.datavalid) &&
882            (ivideo->sisfb_thismonitor.feature & 0xe0))) {
883
884          if(ivideo->sisvga_engine == SIS_315_VGA) {
885             setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
886          }
887
888          if(!(sisfb_bridgeisslave(ivideo))) {
889             setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
890             setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
891          }
892       }
893
894    }
895
896    if(ivideo->currentvbflags & CRT2_LCD) {
897
898       if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
899          if(backlight) {
900             SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
901          } else {
902             SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
903          }
904       } else if(ivideo->sisvga_engine == SIS_315_VGA) {
905          if(ivideo->vbflags & VB_CHRONTEL) {
906             if(backlight) {
907                SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
908             } else {
909                SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
910             }
911          }
912       }
913
914       if(((ivideo->sisvga_engine == SIS_300_VGA) &&
915           (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
916          ((ivideo->sisvga_engine == SIS_315_VGA) &&
917           ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
918           setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
919       }
920
921       if(ivideo->sisvga_engine == SIS_300_VGA) {
922          if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
923             (!(ivideo->vbflags & VB_30xBDH))) {
924             setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
925          }
926       } else if(ivideo->sisvga_engine == SIS_315_VGA) {
927          if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
928             (!(ivideo->vbflags & VB_30xBDH))) {
929             setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
930          }
931       }
932
933    } else if(ivideo->currentvbflags & CRT2_VGA) {
934
935       if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
936          setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
937       }
938
939    }
940
941    return(0);
942 }
943
944 /* ----------- FBDev related routines for all series ----------- */
945
946 static int
947 sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
948 {
949         return (var->bits_per_pixel == 8) ? 256 : 16;
950 }
951
952 static void
953 sisfb_set_vparms(struct sis_video_info *ivideo)
954 {
955         switch(ivideo->video_bpp) {
956         case 8:
957                 ivideo->DstColor = 0x0000;
958                 ivideo->SiS310_AccelDepth = 0x00000000;
959                 ivideo->video_cmap_len = 256;
960                 break;
961         case 16:
962                 ivideo->DstColor = 0x8000;
963                 ivideo->SiS310_AccelDepth = 0x00010000;
964                 ivideo->video_cmap_len = 16;
965                 break;
966         case 32:
967                 ivideo->DstColor = 0xC000;
968                 ivideo->SiS310_AccelDepth = 0x00020000;
969                 ivideo->video_cmap_len = 16;
970                 break;
971         default:
972                 ivideo->video_cmap_len = 16;
973                 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
974                 ivideo->accel = 0;
975                 break;
976         }
977 }
978
979 static int
980 sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
981 {
982         int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
983
984         if(maxyres > 32767) maxyres = 32767;
985
986         return maxyres;
987 }
988
989 static void
990 sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
991 {
992         ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
993         ivideo->scrnpitchCRT1 = ivideo->video_linelength;
994         if(!(ivideo->currentvbflags & CRT1_LCDA)) {
995                 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
996                         ivideo->scrnpitchCRT1 <<= 1;
997                 }
998         }
999
1000 }
1001
1002 static void
1003 sisfb_set_pitch(struct sis_video_info *ivideo)
1004 {
1005         BOOLEAN isslavemode = FALSE;
1006         unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1007         unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1008
1009         if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
1010
1011         /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1012         if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1013                 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1014                 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1015         }
1016
1017         /* We must not set the pitch for CRT2 if bridge is in slave mode */
1018         if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1019                 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1020                 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1021                 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1022         }
1023 }
1024
1025 static void
1026 sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1027 {
1028         ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1029
1030         switch(var->bits_per_pixel) {
1031         case 8:
1032                 var->red.offset = var->green.offset = var->blue.offset = 0;
1033                 var->red.length = var->green.length = var->blue.length = 6;
1034                 break;
1035         case 16:
1036                 var->red.offset = 11;
1037                 var->red.length = 5;
1038                 var->green.offset = 5;
1039                 var->green.length = 6;
1040                 var->blue.offset = 0;
1041                 var->blue.length = 5;
1042                 var->transp.offset = 0;
1043                 var->transp.length = 0;
1044                 break;
1045         case 32:
1046                 var->red.offset = 16;
1047                 var->red.length = 8;
1048                 var->green.offset = 8;
1049                 var->green.length = 8;
1050                 var->blue.offset = 0;
1051                 var->blue.length = 8;
1052                 var->transp.offset = 24;
1053                 var->transp.length = 8;
1054                 break;
1055         }
1056 }
1057
1058 static int
1059 sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1060 {
1061         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1062         unsigned int htotal = 0, vtotal = 0;
1063         unsigned int drate = 0, hrate = 0;
1064         int found_mode = 0;
1065         int old_mode;
1066         u32 pixclock;
1067
1068         htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1069
1070         vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1071
1072         pixclock = var->pixclock;
1073
1074         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1075                 vtotal += var->yres;
1076                 vtotal <<= 1;
1077         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1078                 vtotal += var->yres;
1079                 vtotal <<= 2;
1080         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1081                 vtotal += var->yres;
1082                 vtotal <<= 1;
1083         } else  vtotal += var->yres;
1084
1085         if(!(htotal) || !(vtotal)) {
1086                 DPRINTK("sisfb: Invalid 'var' information\n");
1087                 return -EINVAL;
1088         }
1089
1090         if(pixclock && htotal && vtotal) {
1091                 drate = 1000000000 / pixclock;
1092                 hrate = (drate * 1000) / htotal;
1093                 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1094         } else {
1095                 ivideo->refresh_rate = 60;
1096         }
1097
1098         old_mode = ivideo->sisfb_mode_idx;
1099         ivideo->sisfb_mode_idx = 0;
1100
1101         while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1102                (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1103                 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1104                     (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1105                     (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1106                         ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1107                         found_mode = 1;
1108                         break;
1109                 }
1110                 ivideo->sisfb_mode_idx++;
1111         }
1112
1113         if(found_mode) {
1114                 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1115                                 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1116         } else {
1117                 ivideo->sisfb_mode_idx = -1;
1118         }
1119
1120         if(ivideo->sisfb_mode_idx < 0) {
1121                 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1122                        var->yres, var->bits_per_pixel);
1123                 ivideo->sisfb_mode_idx = old_mode;
1124                 return -EINVAL;
1125         }
1126
1127         if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1128                 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1129                 ivideo->refresh_rate = 60;
1130         }
1131
1132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1133         if(ivideo->sisfb_thismonitor.datavalid) {
1134            if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
1135                                  ivideo->rate_idx, ivideo->refresh_rate)) {
1136               printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1137            }
1138         }
1139 #endif
1140
1141 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1142         if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1143 #else
1144         if(isactive) {
1145 #endif
1146                 sisfb_pre_setmode(ivideo);
1147
1148                 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
1149                         printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1150                         return -EINVAL;
1151                 }
1152
1153                 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1154
1155                 sisfb_post_setmode(ivideo);
1156
1157                 ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1158                 ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1159                 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1160
1161                 sisfb_calc_pitch(ivideo, var);
1162                 sisfb_set_pitch(ivideo);
1163
1164                 ivideo->accel = 0;
1165 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1166 #ifdef STUPID_ACCELF_TEXT_SHIT
1167                 if(var->accel_flags & FB_ACCELF_TEXT) {
1168                         info->flags &= ~FBINFO_HWACCEL_DISABLED;
1169                 } else {
1170                         info->flags |= FBINFO_HWACCEL_DISABLED;
1171                 }
1172 #endif
1173                 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1174 #else
1175                 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1176 #endif
1177
1178                 sisfb_set_vparms(ivideo);
1179
1180                 ivideo->current_width = ivideo->video_width;
1181                 ivideo->current_height = ivideo->video_height;
1182                 ivideo->current_bpp = ivideo->video_bpp;
1183                 ivideo->current_htotal = htotal;
1184                 ivideo->current_vtotal = vtotal;
1185                 ivideo->current_linelength = ivideo->video_linelength;
1186                 ivideo->current_pixclock = var->pixclock;
1187                 ivideo->current_refresh_rate = ivideo->refresh_rate;
1188 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1189                 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1190 #endif
1191         }
1192
1193         return 0;
1194 }
1195
1196 static int
1197 sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1198 {
1199         unsigned int base;
1200
1201         if(var->xoffset > (var->xres_virtual - var->xres)) {
1202                 return -EINVAL;
1203         }
1204         if(var->yoffset > (var->yres_virtual - var->yres)) {
1205                 return -EINVAL;
1206         }
1207
1208         base = (var->yoffset * var->xres_virtual) + var->xoffset;
1209
1210         /* calculate base bpp dep. */
1211         switch(var->bits_per_pixel) {
1212         case 32:
1213                 break;
1214         case 16:
1215                 base >>= 1;
1216                 break;
1217         case 8:
1218         default:
1219                 base >>= 2;
1220                 break;
1221         }
1222         
1223         outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1224
1225         outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1226         outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1227         outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1228         if(ivideo->sisvga_engine == SIS_315_VGA) {
1229                 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1230         }
1231         if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1232                 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1233                 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1234                 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1235                 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1236                 if(ivideo->sisvga_engine == SIS_315_VGA) {
1237                         setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1238                 }
1239         }
1240         return 0;
1241 }
1242
1243 /* ------------ FBDev related routines for 2.4 series ----------- */
1244
1245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1246
1247 static void
1248 sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1249 {
1250         u16 VRE, VBE, VRS, VBS, VDE, VT;
1251         u16 HRE, HBE, HRS, HBS, HDE, HT;
1252         u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
1253         int A, B, C, D, E, F, temp;
1254         unsigned int hrate, drate, maxyres;
1255
1256         inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
1257
1258         if(sr_data & SIS_INTERLACED_MODE)
1259            var->vmode = FB_VMODE_INTERLACED;
1260         else
1261            var->vmode = FB_VMODE_NONINTERLACED;
1262
1263         switch((sr_data & 0x1C) >> 2) {
1264         case SIS_8BPP_COLOR_MODE:
1265                 var->bits_per_pixel = 8;
1266                 break;
1267         case SIS_16BPP_COLOR_MODE:
1268                 var->bits_per_pixel = 16;
1269                 break;
1270         case SIS_32BPP_COLOR_MODE:
1271                 var->bits_per_pixel = 32;
1272                 break;
1273         }
1274
1275         sisfb_bpp_to_var(ivideo, var);
1276         
1277         inSISIDXREG(SISSR, 0x0A, sr_data);
1278         inSISIDXREG(SISCR, 0x06, cr_data);
1279         inSISIDXREG(SISCR, 0x07, cr_data2);
1280
1281         VT = (cr_data & 0xFF) |
1282              ((u16) (cr_data2 & 0x01) << 8) |
1283              ((u16) (cr_data2 & 0x20) << 4) |
1284              ((u16) (sr_data  & 0x01) << 10);
1285         A = VT + 2;
1286
1287         inSISIDXREG(SISCR, 0x12, cr_data);
1288
1289         VDE = (cr_data & 0xff) |
1290               ((u16) (cr_data2 & 0x02) << 7) |
1291               ((u16) (cr_data2 & 0x40) << 3) |
1292               ((u16) (sr_data  & 0x02) << 9);
1293         E = VDE + 1;
1294
1295         inSISIDXREG(SISCR, 0x10, cr_data);
1296
1297         VRS = (cr_data & 0xff) |
1298               ((u16) (cr_data2 & 0x04) << 6) |
1299               ((u16) (cr_data2 & 0x80) << 2) |
1300               ((u16) (sr_data  & 0x08) << 7);
1301         F = VRS + 1 - E;
1302
1303         inSISIDXREG(SISCR, 0x15, cr_data);
1304         inSISIDXREG(SISCR, 0x09, cr_data3);
1305
1306         if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
1307
1308         VBS = (cr_data & 0xff) |
1309               ((u16) (cr_data2 & 0x08) << 5) |
1310               ((u16) (cr_data3 & 0x20) << 4) |
1311               ((u16) (sr_data & 0x04) << 8);
1312
1313         inSISIDXREG(SISCR, 0x16, cr_data);
1314
1315         VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
1316         temp = VBE - ((E - 1) & 511);
1317         B = (temp > 0) ? temp : (temp + 512);
1318
1319         inSISIDXREG(SISCR, 0x11, cr_data);
1320
1321         VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
1322         temp = VRE - ((E + F - 1) & 31);
1323         C = (temp > 0) ? temp : (temp + 32);
1324
1325         D = B - F - C;
1326
1327         var->yres = E;
1328         var->upper_margin = D;
1329         var->lower_margin = F;
1330         var->vsync_len = C;
1331
1332         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1333            var->yres <<= 1;
1334            var->upper_margin <<= 1;
1335            var->lower_margin <<= 1;
1336            var->vsync_len <<= 1;
1337         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1338            var->yres >>= 1;
1339            var->upper_margin >>= 1;
1340            var->lower_margin >>= 1;
1341            var->vsync_len >>= 1;
1342         }
1343
1344         inSISIDXREG(SISSR, 0x0b, sr_data);
1345         inSISIDXREG(SISCR, 0x00, cr_data);
1346
1347         HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
1348         A = HT + 5;
1349
1350         inSISIDXREG(SISCR, 0x01, cr_data);
1351
1352         HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
1353         E = HDE + 1;
1354
1355         inSISIDXREG(SISCR, 0x04, cr_data);
1356
1357         HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
1358         F = HRS - E - 3;
1359
1360         inSISIDXREG(SISCR, 0x02, cr_data);
1361
1362         HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
1363
1364         inSISIDXREG(SISSR, 0x0c, sr_data);
1365         inSISIDXREG(SISCR, 0x03, cr_data);
1366         inSISIDXREG(SISCR, 0x05, cr_data2);
1367
1368         HBE = (cr_data & 0x1f) |
1369               ((u16) (cr_data2 & 0x80) >> 2) |
1370               ((u16) (sr_data  & 0x03) << 6);
1371         HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
1372
1373         temp = HBE - ((E - 1) & 255);
1374         B = (temp > 0) ? temp : (temp + 256);
1375
1376         temp = HRE - ((E + F + 3) & 63);
1377         C = (temp > 0) ? temp : (temp + 64);
1378
1379         D = B - F - C;
1380
1381         var->xres = E * 8;
1382         if(var->xres_virtual < var->xres) {
1383                 var->xres_virtual = var->xres;
1384         }
1385
1386         if((var->xres == 320) &&
1387            (var->yres == 200 || var->yres == 240)) {
1388                 /* Terrible hack, but the correct CRTC data for
1389                  * these modes only produces a black screen...
1390                  */
1391                 var->left_margin = (400 - 376);
1392                 var->right_margin = (328 - 320);
1393                 var->hsync_len = (376 - 328);
1394         } else {
1395                 var->left_margin = D * 8;
1396                 var->right_margin = F * 8;
1397                 var->hsync_len = C * 8;
1398         }
1399         var->activate = FB_ACTIVATE_NOW;
1400
1401         var->sync = 0;
1402
1403         mr_data = inSISREG(SISMISCR);
1404         if(mr_data & 0x80)
1405            var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
1406         else
1407            var->sync |= FB_SYNC_VERT_HIGH_ACT;
1408
1409         if(mr_data & 0x40)
1410            var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
1411         else
1412            var->sync |= FB_SYNC_HOR_HIGH_ACT;
1413
1414         VT += 2;
1415         VT <<= 1;
1416         HT = (HT + 5) * 8;
1417
1418         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1419            VT <<= 1;
1420         }
1421         hrate = ivideo->refresh_rate * VT / 2;
1422         drate = (hrate * HT) / 1000;
1423         var->pixclock = (u32) (1000000000 / drate);
1424
1425         if(ivideo->sisfb_ypan) {
1426            maxyres = sisfb_calc_maxyres(ivideo, var);
1427            if(ivideo->sisfb_max) {
1428               var->yres_virtual = maxyres;
1429            } else {
1430               if(var->yres_virtual > maxyres) {
1431                  var->yres_virtual = maxyres;
1432               }
1433            }
1434            if(var->yres_virtual <= var->yres) {
1435               var->yres_virtual = var->yres;
1436            }
1437         } else {
1438            var->yres_virtual = var->yres;
1439         }
1440
1441 }
1442
1443 static int
1444 sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
1445                          unsigned *transp, struct fb_info *info)
1446 {
1447         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1448
1449         if(regno >= ivideo->video_cmap_len) return 1;
1450
1451         *red   = ivideo->sis_palette[regno].red;
1452         *green = ivideo->sis_palette[regno].green;
1453         *blue  = ivideo->sis_palette[regno].blue;
1454         *transp = 0;
1455
1456         return 0;
1457 }
1458
1459 static int
1460 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1461                            unsigned transp, struct fb_info *info)
1462 {
1463         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1464
1465         if(regno >= ivideo->video_cmap_len) return 1;
1466
1467         ivideo->sis_palette[regno].red   = red;
1468         ivideo->sis_palette[regno].green = green;
1469         ivideo->sis_palette[regno].blue  = blue;
1470
1471         switch(ivideo->video_bpp) {
1472 #ifdef FBCON_HAS_CFB8
1473         case 8:
1474                 outSISREG(SISDACA, regno);
1475                 outSISREG(SISDACD, (red >> 10));
1476                 outSISREG(SISDACD, (green >> 10));
1477                 outSISREG(SISDACD, (blue >> 10));
1478                 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1479                         outSISREG(SISDAC2A, regno);
1480                         outSISREG(SISDAC2D, (red >> 8));
1481                         outSISREG(SISDAC2D, (green >> 8));
1482                         outSISREG(SISDAC2D, (blue >> 8));
1483                 }
1484                 break;
1485 #endif
1486 #ifdef FBCON_HAS_CFB16
1487         case 16:
1488                 ivideo->sis_fbcon_cmap.cfb16[regno] =
1489                     ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1490                 break;
1491 #endif
1492 #ifdef FBCON_HAS_CFB32
1493         case 32:
1494                 red   >>= 8;
1495                 green >>= 8;
1496                 blue  >>= 8;
1497                 ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
1498                 break;
1499 #endif
1500         }
1501
1502         return 0;
1503 }
1504
1505 static void
1506 sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
1507 {
1508         struct sis_video_info    *ivideo = (struct sis_video_info *)info->par;
1509         struct display           *display;
1510         struct display_switch    *sw;
1511         struct fb_fix_screeninfo fix;
1512         long   flags;
1513
1514         display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1515
1516         sisfb_get_fix(&fix, con, info);
1517
1518         display->var = *var;
1519         display->screen_base = (char *)ivideo->video_vbase;
1520         display->visual = fix.visual;
1521         display->type = fix.type;
1522         display->type_aux = fix.type_aux;
1523         display->ypanstep = fix.ypanstep;
1524         display->ywrapstep = fix.ywrapstep;
1525         display->line_length = fix.line_length;
1526         display->can_soft_blank = 1;
1527         display->inverse = ivideo->sisfb_inverse;
1528         display->next_line = fix.line_length;
1529
1530         save_flags(flags);
1531
1532         switch(ivideo->video_bpp) {
1533 #ifdef FBCON_HAS_CFB8
1534         case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
1535                 break;
1536 #endif
1537 #ifdef FBCON_HAS_CFB16
1538         case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
1539                 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
1540                 break;
1541 #endif
1542 #ifdef FBCON_HAS_CFB32
1543         case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
1544                 display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
1545                 break;
1546 #endif
1547         default:sw = &fbcon_dummy;
1548                 break;
1549         }
1550         memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
1551         display->dispsw = &ivideo->sisfb_sw;
1552
1553         restore_flags(flags);
1554
1555         if(ivideo->sisfb_ypan) {
1556             /* display->scrollmode = 0;  */
1557         } else {
1558             display->scrollmode = SCROLL_YREDRAW;
1559             ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
1560         }
1561 }
1562
1563 static void
1564 sisfb_do_install_cmap(int con, struct fb_info *info)
1565 {
1566         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1567
1568         if(con != ivideo->currcon) return;
1569
1570         if(fb_display[con].cmap.len) {
1571                 fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
1572         } else {
1573                 int size = sisfb_get_cmap_len(&fb_display[con].var);
1574                 fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
1575         }
1576 }
1577
1578 static int
1579 sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1580 {
1581         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1582
1583         if(con == -1) {
1584                 memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
1585         } else {
1586                 *var = fb_display[con].var;
1587         }
1588
1589         if(ivideo->sisfb_fstn) {
1590                 if(var->xres == 320 && var->yres == 480) var->yres = 240;
1591         }
1592
1593         return 0;
1594 }
1595
1596 static int
1597 sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
1598 {
1599         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1600         int err;
1601
1602         fb_display[con].var.activate = FB_ACTIVATE_NOW;
1603
1604         if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
1605                 sisfb_crtc_to_var(ivideo, var);
1606                 return -EINVAL;
1607         }
1608
1609         sisfb_crtc_to_var(ivideo, var);
1610
1611         sisfb_set_disp(con, var, info);
1612
1613         if(info->changevar) {
1614                 (*info->changevar)(con);
1615         }
1616
1617         if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
1618                 return err;
1619         }
1620
1621         sisfb_do_install_cmap(con, info);
1622
1623 #if 0   /* Why was this called here? */
1624         unsigned int cols, rows;
1625         cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1626         rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1627         vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1628 #endif
1629         return 0;
1630 }
1631
1632 static int
1633 sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1634 {
1635         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1636         struct display *display;
1637
1638         display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1639
1640         if(con == ivideo->currcon) {
1641
1642                 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1643
1644         } else if(display->cmap.len) {
1645
1646                 fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
1647
1648         } else {
1649
1650                 int size = sisfb_get_cmap_len(&display->var);
1651                 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1652
1653         }
1654
1655         return 0;
1656 }
1657
1658 static int
1659 sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1660 {
1661         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1662         struct display *display;
1663         int err, size;
1664
1665         display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
1666
1667         size = sisfb_get_cmap_len(&display->var);
1668         if(display->cmap.len != size) {
1669                 err = fb_alloc_cmap(&display->cmap, size, 0);
1670                 if(err) return err;
1671         }
1672         
1673         if(con == ivideo->currcon) {
1674                 return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
1675         } else {
1676                 fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
1677         }
1678
1679         return 0;
1680 }
1681
1682 static int
1683 sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
1684 {
1685         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1686         int err;
1687
1688         if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
1689
1690         if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
1691            (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
1692                 return -EINVAL;
1693         }
1694
1695         if(con == ivideo->currcon) {
1696                 if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
1697         }
1698
1699         fb_display[con].var.xoffset = var->xoffset;
1700         fb_display[con].var.yoffset = var->yoffset;
1701
1702         return 0;
1703 }
1704
1705 static int
1706 sisfb_update_var(int con, struct fb_info *info)
1707 {
1708         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1709
1710         return(sisfb_pan_var(ivideo, &fb_display[con].var));
1711 }
1712
1713 static int
1714 sisfb_switch(int con, struct fb_info *info)
1715 {
1716         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1717         int cols, rows;
1718
1719         if(fb_display[ivideo->currcon].cmap.len) {
1720                 fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
1721         }
1722
1723         fb_display[con].var.activate = FB_ACTIVATE_NOW;
1724
1725         if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
1726                                         sizeof(struct fb_var_screeninfo))) {
1727                 ivideo->currcon = con;
1728                 return 1;
1729         }
1730
1731         ivideo->currcon = con;
1732
1733         sisfb_do_set_var(&fb_display[con].var, 1, info);
1734
1735         sisfb_set_disp(con, &fb_display[con].var, info);
1736
1737         sisfb_do_install_cmap(con, info);
1738
1739         cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
1740         rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
1741         vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1742
1743         sisfb_update_var(con, info);
1744
1745         return 1;
1746 }
1747
1748 static void
1749 sisfb_blank(int blank, struct fb_info *info)
1750 {
1751         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1752
1753         sisfb_myblank(ivideo, blank);
1754 }
1755 #endif
1756
1757 /* ------------ FBDev related routines for 2.6 series ----------- */
1758
1759 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1760
1761 static int
1762 sisfb_open(struct fb_info *info, int user)
1763 {
1764         return 0;
1765 }
1766
1767 static int
1768 sisfb_release(struct fb_info *info, int user)
1769 {
1770         return 0;
1771 }
1772
1773 static int
1774 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1775                 unsigned transp, struct fb_info *info)
1776 {
1777         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1778
1779         if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
1780
1781         switch(info->var.bits_per_pixel) {
1782         case 8:
1783                 outSISREG(SISDACA, regno);
1784                 outSISREG(SISDACD, (red >> 10));
1785                 outSISREG(SISDACD, (green >> 10));
1786                 outSISREG(SISDACD, (blue >> 10));
1787                 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1788                         outSISREG(SISDAC2A, regno);
1789                         outSISREG(SISDAC2D, (red >> 8));
1790                         outSISREG(SISDAC2D, (green >> 8));
1791                         outSISREG(SISDAC2D, (blue >> 8));
1792                 }
1793                 break;
1794         case 16:
1795                 ((u32 *)(info->pseudo_palette))[regno] =
1796                     ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
1797                 break;
1798         case 32:
1799                 red >>= 8;
1800                 green >>= 8;
1801                 blue >>= 8;
1802                 ((u32 *)(info->pseudo_palette))[regno] =
1803                                 (red << 16) | (green << 8) | (blue);
1804                 break;
1805         }
1806         return 0;
1807 }
1808
1809 static int
1810 sisfb_set_par(struct fb_info *info)
1811 {
1812         int err;
1813
1814         if((err = sisfb_do_set_var(&info->var, 1, info))) {
1815                 return err;
1816         }
1817 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1818         sisfb_get_fix(&info->fix, info->currcon, info);
1819 #else
1820         sisfb_get_fix(&info->fix, -1, info);
1821 #endif
1822         return 0;
1823 }
1824
1825 static int
1826 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1827 {
1828         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1829         unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1830         unsigned int drate = 0, hrate = 0, maxyres;
1831         int found_mode = 0;
1832         int refresh_rate, search_idx;
1833         BOOLEAN recalc_clock = FALSE;
1834         u32 pixclock;
1835
1836         htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1837
1838         vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1839
1840         pixclock = var->pixclock;
1841
1842         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1843                 vtotal += var->yres;
1844                 vtotal <<= 1;
1845         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1846                 vtotal += var->yres;
1847                 vtotal <<= 2;
1848         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1849                 vtotal += var->yres;
1850                 vtotal <<= 1;
1851         } else  vtotal += var->yres;
1852
1853         if(!(htotal) || !(vtotal)) {
1854                 SISFAIL("sisfb: no valid timing data");
1855         }
1856
1857         search_idx = 0;
1858         while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1859                (sisbios_mode[search_idx].xres <= var->xres) ) {
1860                 if( (sisbios_mode[search_idx].xres == var->xres) &&
1861                     (sisbios_mode[search_idx].yres == var->yres) &&
1862                     (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1863                         if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1864                            found_mode = 1;
1865                            break;
1866                         }
1867                 }
1868                 search_idx++;
1869         }
1870
1871         if(!found_mode) {
1872                 search_idx = 0;
1873                 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1874                    if( (var->xres <= sisbios_mode[search_idx].xres) &&
1875                        (var->yres <= sisbios_mode[search_idx].yres) &&
1876                        (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1877                           if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1878                              found_mode = 1;
1879                              break;
1880                           }
1881                    }
1882                    search_idx++;
1883                 }
1884                 if(found_mode) {
1885                         printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1886                                 var->xres, var->yres, var->bits_per_pixel,
1887                                 sisbios_mode[search_idx].xres,
1888                                 sisbios_mode[search_idx].yres,
1889                                 var->bits_per_pixel);
1890                         var->xres = sisbios_mode[search_idx].xres;
1891                         var->yres = sisbios_mode[search_idx].yres;
1892
1893
1894                 } else {
1895                         printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1896                                 var->xres, var->yres, var->bits_per_pixel);
1897                         return -EINVAL;
1898                 }
1899         }
1900
1901         if( ((ivideo->vbflags & VB_LVDS) ||                     /* Slave modes on LVDS and 301B-DH */
1902              ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1903             (var->bits_per_pixel == 8) ) {
1904                 refresh_rate = 60;
1905                 recalc_clock = TRUE;
1906         } else if( (ivideo->current_htotal == htotal) &&        /* x=x & y=y & c=c -> assume depth change */
1907                    (ivideo->current_vtotal == vtotal) &&
1908                    (ivideo->current_pixclock == pixclock) ) {
1909                 drate = 1000000000 / pixclock;
1910                 hrate = (drate * 1000) / htotal;
1911                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1912         } else if( ( (ivideo->current_htotal != htotal) ||      /* x!=x | y!=y & c=c -> invalid pixclock */
1913                      (ivideo->current_vtotal != vtotal) ) &&
1914                    (ivideo->current_pixclock == var->pixclock) ) {
1915                 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1916                         refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1917                 } else if(ivideo->sisfb_parm_rate != -1) {
1918                         /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1919                         refresh_rate = ivideo->sisfb_parm_rate;
1920                 } else {
1921                         refresh_rate = 60;
1922                 }
1923                 recalc_clock = TRUE;
1924         } else if((pixclock) && (htotal) && (vtotal)) {
1925                 drate = 1000000000 / pixclock;
1926                 hrate = (drate * 1000) / htotal;
1927                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1928         } else if(ivideo->current_refresh_rate) {
1929                 refresh_rate = ivideo->current_refresh_rate;
1930                 recalc_clock = TRUE;
1931         } else {
1932                 refresh_rate = 60;
1933                 recalc_clock = TRUE;
1934         }
1935
1936         myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1937
1938         /* Eventually recalculate timing and clock */
1939         if(recalc_clock) {
1940            if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1941            var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1942                                                 &ivideo->sishw_ext,
1943                                                 sisbios_mode[search_idx].mode_no[ivideo->mni],
1944                                                 myrateindex));
1945            sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1946                                     sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1947            if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1948               var->pixclock <<= 1;
1949            }
1950         }
1951
1952         if(ivideo->sisfb_thismonitor.datavalid) {
1953            if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1954                                  myrateindex, refresh_rate)) {
1955               printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1956            }
1957         }
1958
1959         /* Adapt RGB settings */
1960         sisfb_bpp_to_var(ivideo, var);
1961         
1962         /* Sanity check for offsets */
1963         if(var->xoffset < 0) var->xoffset = 0;
1964         if(var->yoffset < 0) var->yoffset = 0;
1965
1966         if(var->xres > var->xres_virtual) {
1967            var->xres_virtual = var->xres;
1968         }
1969
1970         if(ivideo->sisfb_ypan) {
1971            maxyres = sisfb_calc_maxyres(ivideo, var);
1972            if(ivideo->sisfb_max) {
1973               var->yres_virtual = maxyres;
1974            } else {
1975               if(var->yres_virtual > maxyres) {
1976                  var->yres_virtual = maxyres;
1977               }
1978            }
1979            if(var->yres_virtual <= var->yres) {
1980               var->yres_virtual = var->yres;
1981            }
1982         } else {
1983            if(var->yres != var->yres_virtual) {
1984               var->yres_virtual = var->yres;
1985            }
1986            var->xoffset = 0;
1987            var->yoffset = 0;
1988         }
1989         
1990         /* Truncate offsets to maximum if too high */
1991         if(var->xoffset > var->xres_virtual - var->xres) {
1992            var->xoffset = var->xres_virtual - var->xres - 1;
1993         }
1994
1995         if(var->yoffset > var->yres_virtual - var->yres) {
1996            var->yoffset = var->yres_virtual - var->yres - 1;
1997         }
1998         
1999         /* Set everything else to 0 */
2000         var->red.msb_right = 
2001         var->green.msb_right =
2002         var->blue.msb_right =
2003         var->transp.offset =
2004         var->transp.length =
2005         var->transp.msb_right = 0;
2006
2007         return 0;
2008 }
2009
2010 static int
2011 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2012 {
2013         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2014         int err;
2015
2016         if(var->xoffset > (var->xres_virtual - var->xres)) {
2017                 return -EINVAL;
2018         }
2019         if(var->yoffset > (var->yres_virtual - var->yres)) {
2020                 return -EINVAL;
2021         }
2022
2023         if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2024
2025         if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2026            var->yoffset + info->var.yres > info->var.yres_virtual) {
2027                 return -EINVAL;
2028         }
2029
2030         if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2031
2032         info->var.xoffset = var->xoffset;
2033         info->var.yoffset = var->yoffset;
2034
2035         return 0;
2036 }
2037
2038 static int
2039 sisfb_blank(int blank, struct fb_info *info)
2040 {
2041         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2042
2043         return(sisfb_myblank(ivideo, blank));
2044 }
2045
2046 #endif
2047
2048 /* ----------- FBDev related routines for all series ---------- */
2049
2050 static int
2051 sisfb_ioctl(struct inode *inode, struct file *file,
2052             unsigned int cmd, unsigned long arg,
2053 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2054             int con,
2055 #endif
2056             struct fb_info *info)
2057 {
2058         struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
2059         struct sis_memreq       sismemreq;
2060         struct fb_vblank        sisvbblank;
2061         sisfb_info              x;
2062         u32                     gpu32 = 0;
2063 #ifndef __user
2064 #define __user
2065 #endif
2066         u32 __user              *argp = (u32 __user *)arg;
2067
2068         switch (cmd) {
2069            case FBIO_ALLOC:
2070                 if(!capable(CAP_SYS_RAWIO)) {
2071                         return -EPERM;
2072                 }
2073                 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) {
2074                         return -EFAULT;
2075                 }
2076                 sis_malloc(&sismemreq);
2077                 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
2078                         sis_free((u32)sismemreq.offset);
2079                         return -EFAULT;
2080                 }
2081                 break;
2082
2083            case FBIO_FREE:
2084                 if(!capable(CAP_SYS_RAWIO)) {
2085                         return -EPERM;
2086                 }
2087                 if(get_user(gpu32, argp)) {
2088                         return -EFAULT;
2089                 }
2090                 sis_free(gpu32);
2091                 break;
2092
2093            case FBIOGET_VBLANK:
2094                 sisvbblank.count = 0;
2095                 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2096                 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) {
2097                         return -EFAULT;
2098                 }
2099                 break;
2100
2101            case SISFB_GET_INFO_SIZE:
2102                 return put_user(sizeof(sisfb_info), argp);
2103
2104            case SISFB_GET_INFO_OLD:
2105                 if(ivideo->warncount++ < 50) {
2106                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2107                 }
2108            case SISFB_GET_INFO:  /* For communication with X driver */
2109                 x.sisfb_id         = SISFB_ID;
2110                 x.sisfb_version    = VER_MAJOR;
2111                 x.sisfb_revision   = VER_MINOR;
2112                 x.sisfb_patchlevel = VER_LEVEL;
2113                 x.chip_id = ivideo->chip_id;
2114                 x.memory = ivideo->video_size / 1024;
2115                 x.heapstart = ivideo->heapstart / 1024;
2116                 if(ivideo->modechanged) {
2117                    x.fbvidmode = ivideo->mode_no;
2118                 } else {
2119                    x.fbvidmode = ivideo->modeprechange;
2120                 }
2121                 x.sisfb_caps = ivideo->caps;
2122                 x.sisfb_tqlen = 512; /* yet fixed */
2123                 x.sisfb_pcibus = ivideo->pcibus;
2124                 x.sisfb_pcislot = ivideo->pcislot;
2125                 x.sisfb_pcifunc = ivideo->pcifunc;
2126                 x.sisfb_lcdpdc = ivideo->detectedpdc;
2127                 x.sisfb_lcdpdca = ivideo->detectedpdca;
2128                 x.sisfb_lcda = ivideo->detectedlcda;
2129                 x.sisfb_vbflags = ivideo->vbflags;
2130                 x.sisfb_currentvbflags = ivideo->currentvbflags;
2131                 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2132                 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2133                 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2134                 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2135                 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2136                 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2137                 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2138                 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2139                 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2140                 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2141
2142                 if(copy_to_user((void __user *)arg, &x, sizeof(x))) {
2143                         return -EFAULT;
2144                 }
2145                 break;
2146
2147            case SISFB_GET_VBRSTATUS_OLD:
2148                 if(ivideo->warncount++ < 50) {
2149                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2150                 }
2151            case SISFB_GET_VBRSTATUS:
2152                 if(sisfb_CheckVBRetrace(ivideo)) {
2153                         return put_user((u32)1, argp);
2154                 } else {
2155                         return put_user((u32)0, argp);
2156                 }
2157
2158            case SISFB_GET_AUTOMAXIMIZE_OLD:
2159                 if(ivideo->warncount++ < 50) {
2160                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2161                 }
2162            case SISFB_GET_AUTOMAXIMIZE:
2163                 if(ivideo->sisfb_max)   return put_user((u32)1, argp);
2164                 else                    return put_user((u32)0, argp);
2165
2166            case SISFB_SET_AUTOMAXIMIZE_OLD:
2167                 if(ivideo->warncount++ < 50) {
2168                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2169                 }
2170            case SISFB_SET_AUTOMAXIMIZE:
2171                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2172                         return -EFAULT;
2173                 }
2174                 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2175                 break;
2176
2177            case SISFB_SET_TVPOSOFFSET:
2178                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2179                         return -EFAULT;
2180                 }
2181                 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2182                 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2183                 break;
2184
2185            case SISFB_GET_TVPOSOFFSET:
2186                 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
2187                                 argp);
2188
2189            case SISFB_SET_LOCK:
2190                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2191                         return -EFAULT;
2192                 }
2193                 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2194                 break;
2195
2196            default:
2197                 return -ENOIOCTLCMD;
2198         }
2199         return 0;
2200 }
2201
2202 #ifdef CONFIG_COMPAT
2203 static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info)
2204 {
2205         int ret;
2206         lock_kernel();
2207         ret = sisfb_ioctl(NULL, f, cmd, arg, info);
2208         unlock_kernel();
2209         return ret;
2210 }
2211 #endif
2212
2213 static int
2214 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2215 {
2216         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2217
2218         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2219
2220         strcpy(fix->id, ivideo->myid);
2221
2222         fix->smem_start  = ivideo->video_base;
2223         fix->smem_len    = ivideo->sisfb_mem;
2224         fix->type        = FB_TYPE_PACKED_PIXELS;
2225         fix->type_aux    = 0;
2226         fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2227         fix->xpanstep    = 1;
2228         fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
2229         fix->ywrapstep   = 0;
2230         fix->line_length = ivideo->video_linelength;
2231         fix->mmio_start  = ivideo->mmio_base;
2232         fix->mmio_len    = ivideo->mmio_size;
2233         if(ivideo->sisvga_engine == SIS_300_VGA) {
2234            fix->accel    = FB_ACCEL_SIS_GLAMOUR;
2235         } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2236            fix->accel    = FB_ACCEL_SIS_XABRE;
2237         } else {
2238            fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
2239         }
2240
2241         return 0;
2242 }
2243
2244 /* ----------------  fb_ops structures ----------------- */
2245
2246 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2247 static struct fb_ops sisfb_ops = {
2248         .owner          = THIS_MODULE,
2249         .fb_get_fix     = sisfb_get_fix,
2250         .fb_get_var     = sisfb_get_var,
2251         .fb_set_var     = sisfb_set_var,
2252         .fb_get_cmap    = sisfb_get_cmap,
2253         .fb_set_cmap    = sisfb_set_cmap,
2254         .fb_pan_display = sisfb_pan_display,
2255         .fb_ioctl       = sisfb_ioctl
2256 };
2257 #endif
2258
2259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2260 static struct fb_ops sisfb_ops = {
2261         .owner          = THIS_MODULE,
2262         .fb_open        = sisfb_open,
2263         .fb_release     = sisfb_release,
2264         .fb_check_var   = sisfb_check_var,
2265         .fb_set_par     = sisfb_set_par,
2266         .fb_setcolreg   = sisfb_setcolreg,
2267         .fb_pan_display = sisfb_pan_display,
2268         .fb_blank       = sisfb_blank,
2269         .fb_fillrect    = fbcon_sis_fillrect,
2270         .fb_copyarea    = fbcon_sis_copyarea,
2271         .fb_imageblit   = cfb_imageblit,
2272         .fb_cursor      = soft_cursor,
2273         .fb_sync        = fbcon_sis_sync,
2274         .fb_ioctl       = sisfb_ioctl,
2275 #ifdef CONFIG_COMPAT
2276         .fb_compat_ioctl = sisfb_compat_ioctl,
2277 #endif
2278 };
2279 #endif
2280
2281 /* ---------------- Chip generation dependent routines ---------------- */
2282
2283 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2284 {
2285         struct pci_dev *pdev = NULL;
2286         int nbridgenum, nbridgeidx, i;
2287         const unsigned short nbridgeids[] = {
2288                 PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
2289                 PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
2290                 PCI_DEVICE_ID_SI_730,
2291                 PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
2292                 PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
2293                 PCI_DEVICE_ID_SI_651,
2294                 PCI_DEVICE_ID_SI_740,
2295                 PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760 VGA */
2296                 PCI_DEVICE_ID_SI_741,
2297                 PCI_DEVICE_ID_SI_660,
2298                 PCI_DEVICE_ID_SI_760
2299         };
2300
2301         switch(basechipid) {
2302 #ifdef CONFIG_FB_SIS_300
2303         case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
2304         case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
2305 #endif
2306 #ifdef CONFIG_FB_SIS_315
2307         case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
2308         case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
2309         case SIS_660:   nbridgeidx = 7; nbridgenum = 4; break;
2310 #endif
2311         default:        return NULL;
2312         }
2313         for(i = 0; i < nbridgenum; i++) {
2314                 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2315         }
2316         return pdev;
2317 }
2318
2319 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2320 {
2321 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2322         u8 reg;
2323 #endif
2324
2325         ivideo->video_size = 0;
2326
2327         switch(ivideo->chip) {
2328 #ifdef CONFIG_FB_SIS_300
2329         case SIS_300:
2330                 inSISIDXREG(SISSR, 0x14, reg);
2331                 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2332                 break;
2333         case SIS_540:
2334         case SIS_630:
2335         case SIS_730:
2336                 if(!ivideo->nbridge) return -1;
2337                 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2338                 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2339                 break;
2340 #endif
2341 #ifdef CONFIG_FB_SIS_315
2342         case SIS_315H:
2343         case SIS_315PRO:
2344         case SIS_315:
2345                 inSISIDXREG(SISSR, 0x14, reg);
2346                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2347                 switch((reg >> 2) & 0x03) {
2348                 case 0x01:
2349                 case 0x03:
2350                    ivideo->video_size <<= 1;
2351                    break;
2352                 case 0x02:
2353                    ivideo->video_size += (ivideo->video_size/2);
2354                 }
2355                 break;
2356         case SIS_330:
2357                 inSISIDXREG(SISSR, 0x14, reg);
2358                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2359                 if(reg & 0x0c) ivideo->video_size <<= 1;
2360                 break;
2361         case SIS_550:
2362         case SIS_650:
2363         case SIS_740:
2364                 inSISIDXREG(SISSR, 0x14, reg);
2365                 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2366                 break;
2367         case SIS_661:
2368         case SIS_741:
2369                 inSISIDXREG(SISCR, 0x79, reg);
2370                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2371                 break;
2372         case SIS_660:
2373         case SIS_760:
2374                 inSISIDXREG(SISCR, 0x79, reg);
2375                 reg = (reg & 0xf0) >> 4;
2376                 if(reg) ivideo->video_size = (1 << reg) << 20;
2377                 inSISIDXREG(SISCR, 0x78, reg);
2378                 reg &= 0x30;
2379                 if(reg) {
2380                    if(reg == 0x10) ivideo->video_size += (32 << 20);
2381                    else            ivideo->video_size += (64 << 20);
2382                 }
2383                 break;
2384 #endif
2385         default:
2386                 return -1;
2387         }
2388         return 0;
2389 }
2390
2391 /* -------------- video bridge device detection --------------- */
2392
2393 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2394 {
2395         u8 cr32, temp;
2396
2397 #ifdef CONFIG_FB_SIS_300
2398         if(ivideo->sisvga_engine == SIS_300_VGA) {
2399                 inSISIDXREG(SISSR, 0x17, temp);
2400                 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2401                         /* PAL/NTSC is stored on SR16 on such machines */
2402                         if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2403                                 inSISIDXREG(SISSR, 0x16, temp);
2404                                 if(temp & 0x20)
2405                                         ivideo->vbflags |= TV_PAL;
2406                                 else
2407                                         ivideo->vbflags |= TV_NTSC;
2408                         }
2409                 }
2410         }
2411 #endif
2412
2413         inSISIDXREG(SISCR, 0x32, cr32);
2414
2415         if(cr32 & SIS_CRT1) {
2416                 ivideo->sisfb_crt1off = 0;
2417         } else {
2418                 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2419         }
2420
2421         ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2422
2423         if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2424         if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2425         if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2426
2427         /* Check given parms for hardware compatibility.
2428          * (Cannot do this in the search_xx routines since we don't
2429          * know what hardware we are running on then)
2430          */
2431
2432         if(ivideo->chip != SIS_550) {
2433            ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2434         }
2435
2436         if(ivideo->sisfb_tvplug != -1) {
2437            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2438                (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2439               if(ivideo->sisfb_tvplug & TV_YPBPR) {
2440                  ivideo->sisfb_tvplug = -1;
2441                  printk(KERN_ERR "sisfb: YPbPr not supported\n");
2442               }
2443            }
2444         }
2445         if(ivideo->sisfb_tvplug != -1) {
2446            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2447                (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2448               if(ivideo->sisfb_tvplug & TV_HIVISION) {
2449                  ivideo->sisfb_tvplug = -1;
2450                  printk(KERN_ERR "sisfb: HiVision not supported\n");
2451               }
2452            }
2453         }
2454         if(ivideo->sisfb_tvstd != -1) {
2455            if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2456                (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2457               if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2458                  ivideo->sisfb_tvstd = -1;
2459                  printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2460               }
2461            }
2462         }
2463
2464         /* Detect/set TV plug & type */
2465         if(ivideo->sisfb_tvplug != -1) {
2466                 ivideo->vbflags |= ivideo->sisfb_tvplug;
2467         } else {
2468                 if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2469                 else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2470                 else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2471                 else {
2472                         if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2473                         if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2474                 }
2475         }
2476
2477         if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2478             if(ivideo->sisfb_tvstd != -1) {
2479                ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2480                ivideo->vbflags |= ivideo->sisfb_tvstd;
2481             }
2482             if(ivideo->vbflags & TV_SCART) {
2483                ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2484                ivideo->vbflags |= TV_PAL;
2485             }
2486             if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2487                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2488                         inSISIDXREG(SISSR, 0x38, temp);
2489                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2490                         else            ivideo->vbflags |= TV_NTSC;
2491                 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2492                         inSISIDXREG(SISSR, 0x38, temp);
2493                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2494                         else            ivideo->vbflags |= TV_NTSC;
2495                 } else {
2496                         inSISIDXREG(SISCR, 0x79, temp);
2497                         if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2498                         else            ivideo->vbflags |= TV_NTSC;
2499                 }
2500             }
2501         }
2502
2503         /* Copy forceCRT1 option to CRT1off if option is given */
2504         if(ivideo->sisfb_forcecrt1 != -1) {
2505            ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2506         }
2507 }
2508
2509 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2510 {
2511         char stdstr[]    = "sisfb: Detected";
2512         char bridgestr[] = "video bridge";
2513         u8 vb_chipid;
2514         u8 reg;
2515
2516         inSISIDXREG(SISPART4, 0x00, vb_chipid);
2517         switch(vb_chipid) {
2518         case 0x01:
2519                 inSISIDXREG(SISPART4, 0x01, reg);
2520                 if(reg < 0xb0) {
2521                         ivideo->vbflags |= VB_301;
2522                         printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2523                 } else if(reg < 0xc0) {
2524                         ivideo->vbflags |= VB_301B;
2525                         inSISIDXREG(SISPART4,0x23,reg);
2526                         if(!(reg & 0x02)) {
2527                            ivideo->vbflags |= VB_30xBDH;
2528                            printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2529                         } else {
2530                            printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2531                         }
2532                 } else if(reg < 0xd0) {
2533                         ivideo->vbflags |= VB_301C;
2534                         printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2535                 } else if(reg < 0xe0) {
2536                         ivideo->vbflags |= VB_301LV;
2537                         printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2538                 } else if(reg <= 0xe1) {
2539                         inSISIDXREG(SISPART4,0x39,reg);
2540                         if(reg == 0xff) {
2541                            ivideo->vbflags |= VB_302LV;
2542                            printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2543                         } else {
2544                            ivideo->vbflags |= VB_301C;
2545                            printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2546 #if 0
2547                            ivideo->vbflags |= VB_302ELV;
2548                            printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2549 #endif
2550                         }
2551                 }
2552                 break;
2553         case 0x02:
2554                 ivideo->vbflags |= VB_302B;
2555                 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2556                 break;
2557         }
2558
2559         if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2560                 inSISIDXREG(SISCR, 0x37, reg);
2561                 reg &= SIS_EXTERNAL_CHIP_MASK;
2562                 reg >>= 1;
2563                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2564 #ifdef CONFIG_FB_SIS_300
2565                         switch(reg) {
2566                            case SIS_EXTERNAL_CHIP_LVDS:
2567                                 ivideo->vbflags |= VB_LVDS;
2568                                 break;
2569                            case SIS_EXTERNAL_CHIP_TRUMPION:
2570                                 ivideo->vbflags |= VB_TRUMPION;
2571                                 break;
2572                            case SIS_EXTERNAL_CHIP_CHRONTEL:
2573                                 ivideo->vbflags |= VB_CHRONTEL;
2574                                 break;
2575                            case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2576                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2577                                 break;
2578                         }
2579                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2580 #endif
2581                 } else if(ivideo->chip < SIS_661) {
2582 #ifdef CONFIG_FB_SIS_315
2583                         switch (reg) {
2584                            case SIS310_EXTERNAL_CHIP_LVDS:
2585                                 ivideo->vbflags |= VB_LVDS;
2586                                 break;
2587                            case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2588                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2589                                 break;
2590                         }
2591                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2592 #endif
2593                 } else if(ivideo->chip >= SIS_661) {
2594 #ifdef CONFIG_FB_SIS_315
2595                         inSISIDXREG(SISCR, 0x38, reg);
2596                         reg >>= 5;
2597                         switch(reg) {
2598                            case 0x02:
2599                                 ivideo->vbflags |= VB_LVDS;
2600                                 break;
2601                            case 0x03:
2602                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2603                                 break;
2604                            case 0x04:
2605                                 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2606                                 break;
2607                         }
2608                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2609 #endif
2610                 }
2611                 if(ivideo->vbflags & VB_LVDS) {
2612                    printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2613                 }
2614                 if(ivideo->vbflags & VB_TRUMPION) {
2615                    printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2616                 }
2617                 if(ivideo->vbflags & VB_CHRONTEL) {
2618                    printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2619                 }
2620                 if(ivideo->vbflags & VB_CONEXANT) {
2621                    printk(KERN_INFO "%s Conexant external device\n", stdstr);
2622                 }
2623         }
2624
2625         if(ivideo->vbflags & VB_SISBRIDGE) {
2626                 SiS_Sense30x(ivideo);
2627         } else if(ivideo->vbflags & VB_CHRONTEL) {
2628                 SiS_SenseCh(ivideo);
2629         }
2630 }
2631
2632 /* ------------------ Sensing routines ------------------ */
2633
2634 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2635 {
2636     unsigned short old;
2637     int count = 48;
2638
2639     old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2640     do {
2641         if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2642     } while(count--);
2643     return (count == -1) ? FALSE : TRUE;
2644 }
2645
2646 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2647 {
2648     BOOLEAN mustwait = FALSE;
2649     u8  sr1F, cr17;
2650 #ifdef CONFIG_FB_SIS_315
2651     u8  cr63=0;
2652 #endif
2653     u16 temp = 0xffff;
2654     int i;
2655
2656     inSISIDXREG(SISSR,0x1F,sr1F);
2657     orSISIDXREG(SISSR,0x1F,0x04);
2658     andSISIDXREG(SISSR,0x1F,0x3F);
2659     if(sr1F & 0xc0) mustwait = TRUE;
2660
2661 #ifdef CONFIG_FB_SIS_315
2662     if(ivideo->sisvga_engine == SIS_315_VGA) {
2663        inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2664        cr63 &= 0x40;
2665        andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2666     }
2667 #endif
2668
2669     inSISIDXREG(SISCR,0x17,cr17);
2670     cr17 &= 0x80;
2671     if(!cr17) {
2672        orSISIDXREG(SISCR,0x17,0x80);
2673        mustwait = TRUE;
2674        outSISIDXREG(SISSR, 0x00, 0x01);
2675        outSISIDXREG(SISSR, 0x00, 0x03);
2676     }
2677
2678     if(mustwait) {
2679        for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2680     }
2681
2682 #ifdef CONFIG_FB_SIS_315
2683     if(ivideo->chip >= SIS_330) {
2684        andSISIDXREG(SISCR,0x32,~0x20);
2685        if(ivideo->chip >= SIS_340) {
2686           outSISIDXREG(SISCR, 0x57, 0x4a);
2687        } else {
2688           outSISIDXREG(SISCR, 0x57, 0x5f);
2689        }
2690        orSISIDXREG(SISCR, 0x53, 0x02);
2691        while((inSISREG(SISINPSTAT)) & 0x01)    break;
2692        while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2693        if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2694        andSISIDXREG(SISCR, 0x53, 0xfd);
2695        andSISIDXREG(SISCR, 0x57, 0x00);
2696     }
2697 #endif
2698
2699     if(temp == 0xffff) {
2700        i = 3;
2701        do {
2702           temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2703        } while(((temp == 0) || (temp == 0xffff)) && i--);
2704
2705        if((temp == 0) || (temp == 0xffff)) {
2706           if(sisfb_test_DDC1(ivideo)) temp = 1;
2707        }
2708     }
2709
2710     if((temp) && (temp != 0xffff)) {
2711        orSISIDXREG(SISCR,0x32,0x20);
2712     }
2713
2714 #ifdef CONFIG_FB_SIS_315
2715     if(ivideo->sisvga_engine == SIS_315_VGA) {
2716        setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2717     }
2718 #endif
2719
2720     setSISIDXREG(SISCR,0x17,0x7F,cr17);
2721
2722     outSISIDXREG(SISSR,0x1F,sr1F);
2723 }
2724
2725 /* Determine and detect attached devices on SiS30x */
2726 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2727 {
2728     int temp, mytest, result, i, j;
2729
2730     for(j = 0; j < 10; j++) {
2731        result = 0;
2732        for(i = 0; i < 3; i++) {
2733           mytest = test;
2734           outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2735           temp = (type >> 8) | (mytest & 0x00ff);
2736           setSISIDXREG(SISPART4,0x10,0xe0,temp);
2737           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2738           mytest >>= 8;
2739           mytest &= 0x7f;
2740           inSISIDXREG(SISPART4,0x03,temp);
2741           temp ^= 0x0e;
2742           temp &= mytest;
2743           if(temp == mytest) result++;
2744 #if 1
2745           outSISIDXREG(SISPART4,0x11,0x00);
2746           andSISIDXREG(SISPART4,0x10,0xe0);
2747           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2748 #endif
2749        }
2750        if((result == 0) || (result >= 2)) break;
2751     }
2752     return(result);
2753 }
2754
2755 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2756 {
2757     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2758     u16 svhs=0, svhs_c=0;
2759     u16 cvbs=0, cvbs_c=0;
2760     u16 vga2=0, vga2_c=0;
2761     int myflag, result;
2762     char stdstr[] = "sisfb: Detected";
2763     char tvstr[]  = "TV connected to";
2764
2765     if(ivideo->vbflags & VB_301) {
2766        svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2767        inSISIDXREG(SISPART4,0x01,myflag);
2768        if(myflag & 0x04) {
2769           svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2770        }
2771     } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2772        svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2773     } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2774        svhs = 0x0200; cvbs = 0x0100;
2775     } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2776        svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2777     } else return;
2778
2779     vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2780     if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2781        svhs_c = 0x0408; cvbs_c = 0x0808;
2782     }
2783     biosflag = 2;
2784
2785     if(ivideo->chip == SIS_300) {
2786        inSISIDXREG(SISSR,0x3b,myflag);
2787        if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2788     }
2789
2790     inSISIDXREG(SISSR,0x1e,backupSR_1e);
2791     orSISIDXREG(SISSR,0x1e,0x20);
2792
2793     inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2794     if(ivideo->vbflags & VB_301C) {
2795        setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2796     } else {
2797        orSISIDXREG(SISPART4,0x0d,0x04);
2798     }
2799     SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2800
2801     inSISIDXREG(SISPART2,0x00,backupP2_00);
2802     outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2803
2804     inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2805     if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2806        outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2807     }
2808
2809     if(!(ivideo->vbflags & VB_301C)) {
2810        SISDoSense(ivideo, 0, 0);
2811     }
2812
2813     andSISIDXREG(SISCR, 0x32, ~0x14);
2814
2815     if(vga2_c || vga2) {
2816        if(SISDoSense(ivideo, vga2, vga2_c)) {
2817           if(biosflag & 0x01) {
2818              printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2819              orSISIDXREG(SISCR, 0x32, 0x04);
2820           } else {
2821              printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2822              orSISIDXREG(SISCR, 0x32, 0x10);
2823           }
2824        }
2825     }
2826
2827     andSISIDXREG(SISCR, 0x32, 0x3f);
2828
2829     if(ivideo->vbflags & VB_301C) {
2830        orSISIDXREG(SISPART4,0x0d,0x04);
2831     }
2832
2833     if((ivideo->sisvga_engine == SIS_315_VGA) &&
2834        (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2835        outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2836        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2837        if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2838           if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2839              printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2840              orSISIDXREG(SISCR,0x32,0x80);
2841           }
2842        }
2843        outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2844     }
2845
2846     andSISIDXREG(SISCR, 0x32, ~0x03);
2847
2848     if(!(ivideo->vbflags & TV_YPBPR)) {
2849        if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2850           printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2851           orSISIDXREG(SISCR, 0x32, 0x02);
2852        }
2853        if((biosflag & 0x02) || (!result)) {
2854           if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2855              printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2856              orSISIDXREG(SISCR, 0x32, 0x01);
2857           }
2858        }
2859     }
2860
2861     SISDoSense(ivideo, 0, 0);
2862
2863     outSISIDXREG(SISPART2,0x00,backupP2_00);
2864     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2865     outSISIDXREG(SISSR,0x1e,backupSR_1e);
2866
2867     if(ivideo->vbflags & VB_301C) {
2868        inSISIDXREG(SISPART2,0x00,biosflag);
2869        if(biosflag & 0x20) {
2870           for(myflag = 2; myflag > 0; myflag--) {
2871              biosflag ^= 0x20;
2872              outSISIDXREG(SISPART2,0x00,biosflag);
2873           }
2874        }
2875     }
2876
2877     outSISIDXREG(SISPART2,0x00,backupP2_00);
2878 }
2879
2880 /* Determine and detect attached TV's on Chrontel */
2881 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2882 {
2883 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2884     u8 temp1, temp2;
2885     char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2886 #endif
2887 #ifdef CONFIG_FB_SIS_300
2888     unsigned char test[3];
2889     int i;
2890 #endif
2891
2892     if(ivideo->chip < SIS_315H) {
2893
2894 #ifdef CONFIG_FB_SIS_300
2895        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2896        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2897        SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2898        temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2899        /* See Chrontel TB31 for explanation */
2900        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2901        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2902           SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2903           SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2904        }
2905        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2906        if(temp2 != temp1) temp1 = temp2;
2907
2908        if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2909            /* Read power status */
2910            temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2911            if((temp1 & 0x03) != 0x03) {
2912                 /* Power all outputs */
2913                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2914                 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2915            }
2916            /* Sense connected TV devices */
2917            for(i = 0; i < 3; i++) {
2918                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2919                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2920                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2921                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2922                temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2923                if(!(temp1 & 0x08))       test[i] = 0x02;
2924                else if(!(temp1 & 0x02))  test[i] = 0x01;
2925                else                      test[i] = 0;
2926                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2927            }
2928
2929            if(test[0] == test[1])      temp1 = test[0];
2930            else if(test[0] == test[2]) temp1 = test[0];
2931            else if(test[1] == test[2]) temp1 = test[1];
2932            else {
2933                 printk(KERN_INFO
2934                         "sisfb: TV detection unreliable - test results varied\n");
2935                 temp1 = test[2];
2936            }
2937            if(temp1 == 0x02) {
2938                 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2939                 ivideo->vbflags |= TV_SVIDEO;
2940                 orSISIDXREG(SISCR, 0x32, 0x02);
2941                 andSISIDXREG(SISCR, 0x32, ~0x05);
2942            } else if (temp1 == 0x01) {
2943                 printk(KERN_INFO "%s CVBS output\n", stdstr);
2944                 ivideo->vbflags |= TV_AVIDEO;
2945                 orSISIDXREG(SISCR, 0x32, 0x01);
2946                 andSISIDXREG(SISCR, 0x32, ~0x06);
2947            } else {
2948                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2949                 andSISIDXREG(SISCR, 0x32, ~0x07);
2950            }
2951        } else if(temp1 == 0) {
2952           SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2953           andSISIDXREG(SISCR, 0x32, ~0x07);
2954        }
2955        /* Set general purpose IO for Chrontel communication */
2956        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2957 #endif
2958
2959     } else {
2960
2961 #ifdef CONFIG_FB_SIS_315
2962         ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2963         temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2964         SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2965         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2966         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2967         temp2 |= 0x01;
2968         SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2969         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2970         temp2 ^= 0x01;
2971         SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2972         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2973         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2974         SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2975         temp1 = 0;
2976         if(temp2 & 0x02) temp1 |= 0x01;
2977         if(temp2 & 0x10) temp1 |= 0x01;
2978         if(temp2 & 0x04) temp1 |= 0x02;
2979         if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2980         switch(temp1) {
2981         case 0x01:
2982              printk(KERN_INFO "%s CVBS output\n", stdstr);
2983              ivideo->vbflags |= TV_AVIDEO;
2984              orSISIDXREG(SISCR, 0x32, 0x01);
2985              andSISIDXREG(SISCR, 0x32, ~0x06);
2986              break;
2987         case 0x02:
2988              printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2989              ivideo->vbflags |= TV_SVIDEO;
2990              orSISIDXREG(SISCR, 0x32, 0x02);
2991              andSISIDXREG(SISCR, 0x32, ~0x05);
2992              break;
2993         case 0x04:
2994              printk(KERN_INFO "%s SCART output\n", stdstr);
2995              orSISIDXREG(SISCR, 0x32, 0x04);
2996              andSISIDXREG(SISCR, 0x32, ~0x03);
2997              break;
2998         default:
2999              andSISIDXREG(SISCR, 0x32, ~0x07);
3000         }
3001 #endif
3002     }
3003 }
3004
3005 /* ------------------------ Heap routines -------------------------- */
3006
3007 static u32 __devinit
3008 sisfb_getheapstart(struct sis_video_info *ivideo)
3009 {
3010         u32 ret = ivideo->sisfb_parm_mem * 1024;
3011         u32 max = ivideo->video_size - ivideo->hwcursor_size;
3012         u32 def;
3013
3014         /* Calculate heap start = end of memory for console
3015          *
3016          * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3017          * C = console, D = heap, H = HWCursor, Q = cmd-queue
3018          *
3019          * Basically given by "mem" parameter
3020          *
3021          * maximum = videosize - cmd_queue - hwcursor
3022          *           (results in a heap of size 0)
3023          * default = SiS 300: depends on videosize
3024          *           SiS 315/330: 32k below max
3025          */
3026
3027         if(ivideo->sisvga_engine == SIS_300_VGA) {
3028            max -= TURBO_QUEUE_AREA_SIZE;
3029            if(ivideo->video_size > 0x1000000) {
3030               def = 0xc00000;
3031            } else if(ivideo->video_size > 0x800000) {
3032               def = 0x800000;
3033            } else {
3034               def = 0x400000;
3035            }
3036         } else {
3037            max -= COMMAND_QUEUE_AREA_SIZE;
3038            def = max - 0x8000;
3039         }
3040
3041         if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3042            ret = def;
3043         }
3044
3045         return ret;
3046 }
3047
3048 static int __devinit
3049 sisfb_heap_init(struct sis_video_info *ivideo)
3050 {
3051      SIS_OH *poh;
3052
3053      ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3054
3055      ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3056      ivideo->sisfb_heap_end   = ivideo->video_vbase + ivideo->video_size;
3057
3058      /* Initialize command queue (We use MMIO only) */
3059
3060 #ifdef CONFIG_FB_SIS_315
3061      if(ivideo->sisvga_engine == SIS_315_VGA) {
3062         u32 tempq = 0;
3063         u8  temp = 0;
3064
3065         ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3066
3067         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3068         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3069
3070         tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3071         MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3072
3073         temp = SIS_CMD_QUEUE_SIZE_512k;
3074         temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3075         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3076
3077         tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3078         MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3079
3080         ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3081      }
3082 #endif
3083
3084 #ifdef CONFIG_FB_SIS_300
3085      if(ivideo->sisvga_engine == SIS_300_VGA) {
3086         unsigned long tqueue_pos;
3087         u8 tq_state;
3088
3089         ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3090
3091         tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3092
3093         inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3094         tq_state |= 0xf0;
3095         tq_state &= 0xfc;
3096         tq_state |= (u8)(tqueue_pos >> 8);
3097         outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3098
3099         outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3100
3101         ivideo->caps |= TURBO_QUEUE_CAP;
3102      }
3103 #endif
3104
3105      /* Reserve memory for the HWCursor */
3106      ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3107      ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3108      ivideo->caps |= HW_CURSOR_CAP;
3109
3110      ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3111
3112      if(ivideo->cardnumber == 0) {
3113
3114         printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3115                 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3116
3117         sisfb_heap.vinfo = ivideo;
3118
3119         sisfb_heap.poha_chain = NULL;
3120         sisfb_heap.poh_freelist = NULL;
3121
3122         poh = sisfb_poh_new_node();
3123         if(poh == NULL) return 1;
3124
3125         poh->poh_next = &sisfb_heap.oh_free;
3126         poh->poh_prev = &sisfb_heap.oh_free;
3127         poh->size = ivideo->sisfb_heap_size;
3128         poh->offset = ivideo->heapstart;
3129
3130         sisfb_heap.oh_free.poh_next = poh;
3131         sisfb_heap.oh_free.poh_prev = poh;
3132         sisfb_heap.oh_free.size = 0;
3133         sisfb_heap.max_freesize = poh->size;
3134
3135         sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3136         sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3137         sisfb_heap.oh_used.size = SENTINEL;
3138
3139      } else {
3140
3141         printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3142
3143      }
3144
3145      return 0;
3146 }
3147
3148 static SIS_OH *
3149 sisfb_poh_new_node(void)
3150 {
3151         int           i;
3152         unsigned long cOhs;
3153         SIS_OHALLOC   *poha;
3154         SIS_OH        *poh;
3155
3156         if(sisfb_heap.poh_freelist == NULL) {
3157                 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3158                 if(!poha) return NULL;
3159
3160                 poha->poha_next = sisfb_heap.poha_chain;
3161                 sisfb_heap.poha_chain = poha;
3162
3163                 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3164
3165                 poh = &poha->aoh[0];
3166                 for(i = cOhs - 1; i != 0; i--) {
3167                         poh->poh_next = poh + 1;
3168                         poh = poh + 1;
3169                 }
3170
3171                 poh->poh_next = NULL;
3172                 sisfb_heap.poh_freelist = &poha->aoh[0];
3173         }
3174
3175         poh = sisfb_heap.poh_freelist;
3176         sisfb_heap.poh_freelist = poh->poh_next;
3177
3178         return (poh);
3179 }
3180
3181 static SIS_OH *
3182 sisfb_poh_allocate(u32 size)
3183 {
3184         SIS_OH *pohThis;
3185         SIS_OH *pohRoot;
3186         int     bAllocated = 0;
3187
3188         if(size > sisfb_heap.max_freesize) {
3189                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3190                         (unsigned int) size / 1024);
3191                 return (NULL);
3192         }
3193
3194         pohThis = sisfb_heap.oh_free.poh_next;
3195
3196         while(pohThis != &sisfb_heap.oh_free) {
3197                 if (size <= pohThis->size) {
3198                         bAllocated = 1;
3199                         break;
3200                 }
3201                 pohThis = pohThis->poh_next;
3202         }
3203
3204         if(!bAllocated) {
3205                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3206                         (unsigned int) size / 1024);
3207                 return (NULL);
3208         }
3209
3210         if(size == pohThis->size) {
3211                 pohRoot = pohThis;
3212                 sisfb_delete_node(pohThis);
3213         } else {
3214                 pohRoot = sisfb_poh_new_node();
3215
3216                 if(pohRoot == NULL) {
3217                         return (NULL);
3218                 }
3219
3220                 pohRoot->offset = pohThis->offset;
3221                 pohRoot->size = size;
3222
3223                 pohThis->offset += size;
3224                 pohThis->size -= size;
3225         }
3226
3227         sisfb_heap.max_freesize -= size;
3228
3229         pohThis = &sisfb_heap.oh_used;
3230         sisfb_insert_node(pohThis, pohRoot);
3231
3232         return (pohRoot);
3233 }
3234
3235 static void
3236 sisfb_delete_node(SIS_OH *poh)
3237 {
3238         SIS_OH *poh_prev;
3239         SIS_OH *poh_next;
3240
3241         poh_prev = poh->poh_prev;
3242         poh_next = poh->poh_next;
3243
3244         poh_prev->poh_next = poh_next;
3245         poh_next->poh_prev = poh_prev;
3246 }
3247
3248 static void
3249 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3250 {
3251         SIS_OH *pohTemp;
3252
3253         pohTemp = pohList->poh_next;
3254
3255         pohList->poh_next = poh;
3256         pohTemp->poh_prev = poh;
3257
3258         poh->poh_prev = pohList;
3259         poh->poh_next = pohTemp;
3260 }
3261
3262 static SIS_OH *
3263 sisfb_poh_free(u32 base)
3264 {
3265         SIS_OH *pohThis;
3266         SIS_OH *poh_freed;
3267         SIS_OH *poh_prev;
3268         SIS_OH *poh_next;
3269         u32     ulUpper;
3270         u32     ulLower;
3271         int     foundNode = 0;
3272
3273         poh_freed = sisfb_heap.oh_used.poh_next;
3274
3275         while(poh_freed != &sisfb_heap.oh_used) {
3276                 if(poh_freed->offset == base) {
3277                         foundNode = 1;
3278                         break;
3279                 }
3280
3281                 poh_freed = poh_freed->poh_next;
3282         }
3283
3284         if(!foundNode) return(NULL);
3285
3286         sisfb_heap.max_freesize += poh_freed->size;
3287
3288         poh_prev = poh_next = NULL;
3289         ulUpper = poh_freed->offset + poh_freed->size;
3290         ulLower = poh_freed->offset;
3291
3292         pohThis = sisfb_heap.oh_free.poh_next;
3293
3294         while(pohThis != &sisfb_heap.oh_free) {
3295                 if(pohThis->offset == ulUpper) {
3296                         poh_next = pohThis;
3297                 } else if((pohThis->offset + pohThis->size) == ulLower) {
3298                         poh_prev = pohThis;
3299                 }
3300                 pohThis = pohThis->poh_next;
3301         }
3302
3303         sisfb_delete_node(poh_freed);
3304
3305         if(poh_prev && poh_next) {
3306                 poh_prev->size += (poh_freed->size + poh_next->size);
3307                 sisfb_delete_node(poh_next);
3308                 sisfb_free_node(poh_freed);
3309                 sisfb_free_node(poh_next);
3310                 return(poh_prev);
3311         }
3312
3313         if(poh_prev) {
3314                 poh_prev->size += poh_freed->size;
3315                 sisfb_free_node(poh_freed);
3316                 return(poh_prev);
3317         }
3318
3319         if(poh_next) {
3320                 poh_next->size += poh_freed->size;
3321                 poh_next->offset = poh_freed->offset;
3322                 sisfb_free_node(poh_freed);
3323                 return(poh_next);
3324         }
3325
3326         sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3327
3328         return(poh_freed);
3329 }
3330
3331 static void
3332 sisfb_free_node(SIS_OH *poh)
3333 {
3334         if(poh == NULL) return;
3335
3336         poh->poh_next = sisfb_heap.poh_freelist;
3337         sisfb_heap.poh_freelist = poh;
3338 }
3339
3340 void
3341 sis_malloc(struct sis_memreq *req)
3342 {
3343         struct sis_video_info *ivideo = sisfb_heap.vinfo;
3344         SIS_OH *poh = NULL;
3345
3346         if((ivideo) && (!ivideo->havenoheap)) {
3347            poh = sisfb_poh_allocate((u32)req->size);
3348         }
3349
3350         if(poh == NULL) {
3351            req->offset = req->size = 0;
3352            DPRINTK("sisfb: Video RAM allocation failed\n");
3353         } else {
3354            req->offset = poh->offset;
3355            req->size = poh->size;
3356            DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3357                     (poh->offset + ivideo->video_vbase));
3358         }
3359 }
3360
3361 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3362
3363 void
3364 sis_free(u32 base)
3365 {
3366         struct sis_video_info *ivideo = sisfb_heap.vinfo;
3367         SIS_OH *poh;
3368
3369         if((!ivideo) || (ivideo->havenoheap)) return;
3370
3371         poh = sisfb_poh_free((u32)base);
3372
3373         if(poh == NULL) {
3374                 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3375                         (unsigned int) base);
3376         }
3377 }
3378
3379 /* --------------------- SetMode routines ------------------------- */
3380
3381 static void
3382 sisfb_pre_setmode(struct sis_video_info *ivideo)
3383 {
3384         u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3385         int tvregnum = 0;
3386
3387         ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3388
3389         inSISIDXREG(SISCR, 0x31, cr31);
3390         cr31 &= ~0x60;
3391         cr31 |= 0x04;
3392
3393         cr33 = ivideo->rate_idx & 0x0F;
3394
3395 #ifdef CONFIG_FB_SIS_315
3396         if(ivideo->sisvga_engine == SIS_315_VGA) {
3397            if(ivideo->chip >= SIS_661) {
3398               inSISIDXREG(SISCR, 0x38, cr38);
3399               cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3400            } else {
3401               tvregnum = 0x38;
3402               inSISIDXREG(SISCR, tvregnum, cr38);
3403               cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3404            }
3405         }
3406 #endif
3407 #ifdef CONFIG_FB_SIS_300
3408         if(ivideo->sisvga_engine == SIS_300_VGA) {
3409            tvregnum = 0x35;
3410            inSISIDXREG(SISCR, tvregnum, cr38);
3411         }
3412 #endif
3413
3414         SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3415         SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3416
3417         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3418
3419            case CRT2_TV:
3420               cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3421               if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3422 #ifdef CONFIG_FB_SIS_315
3423                  if(ivideo->chip >= SIS_661) {
3424                     cr38 |= 0x04;
3425                     if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3426                     else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3427                     else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3428                     cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3429                     cr35 &= ~0x01;
3430                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3431                  } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3432                     cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3433                     cr38 |= 0x08;
3434                     if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3435                     else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3436                     else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3437                     cr31 &= ~0x01;
3438                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3439                  }
3440 #endif
3441               } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3442                  if(ivideo->chip >= SIS_661) {
3443                     cr38 |= 0x04;
3444                     cr35 |= 0x60;
3445                  } else {
3446                     cr30 |= 0x80;
3447                  }
3448                  cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3449                  cr31 |= 0x01;
3450                  cr35 |= 0x01;
3451                  ivideo->currentvbflags |= TV_HIVISION;
3452               } else if(ivideo->vbflags & TV_SCART) {
3453                  cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3454                  cr31 |= 0x01;
3455                  cr35 |= 0x01;
3456                  ivideo->currentvbflags |= TV_SCART;
3457               } else {
3458                  if(ivideo->vbflags & TV_SVIDEO) {
3459                     cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3460                     ivideo->currentvbflags |= TV_SVIDEO;
3461                  }
3462                  if(ivideo->vbflags & TV_AVIDEO) {
3463                     cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3464                     ivideo->currentvbflags |= TV_AVIDEO;
3465                  }
3466               }
3467               cr31 |= SIS_DRIVER_MODE;
3468
3469               if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3470                  if(ivideo->vbflags & TV_PAL) {
3471                     cr31 |= 0x01; cr35 |= 0x01;
3472                     ivideo->currentvbflags |= TV_PAL;
3473                     if(ivideo->vbflags & TV_PALM) {
3474                        cr38 |= 0x40; cr35 |= 0x04;
3475                        ivideo->currentvbflags |= TV_PALM;
3476                     } else if(ivideo->vbflags & TV_PALN) {
3477                        cr38 |= 0x80; cr35 |= 0x08;
3478                        ivideo->currentvbflags |= TV_PALN;
3479                     }
3480                  } else {
3481                     cr31 &= ~0x01; cr35 &= ~0x01;
3482                     ivideo->currentvbflags |= TV_NTSC;
3483                     if(ivideo->vbflags & TV_NTSCJ) {
3484                        cr38 |= 0x40; cr35 |= 0x02;
3485                        ivideo->currentvbflags |= TV_NTSCJ;
3486                     }
3487                  }
3488               }
3489               break;
3490
3491            case CRT2_LCD:
3492               cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3493               cr31 |= SIS_DRIVER_MODE;
3494               SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3495               SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3496               break;
3497
3498            case CRT2_VGA:
3499               cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3500               cr31 |= SIS_DRIVER_MODE;
3501               if(ivideo->sisfb_nocrt2rate) {
3502                  cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3503               } else {
3504                  cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3505               }
3506               break;
3507
3508            default:     /* disable CRT2 */
3509               cr30 = 0x00;
3510               cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3511         }
3512
3513         outSISIDXREG(SISCR, 0x30, cr30);
3514         outSISIDXREG(SISCR, 0x33, cr33);
3515
3516         if(ivideo->chip >= SIS_661) {
3517 #ifdef CONFIG_FB_SIS_315
3518            cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3519            setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3520            cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3521            setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3522 #endif
3523         } else if(ivideo->chip != SIS_300) {
3524            outSISIDXREG(SISCR, tvregnum, cr38);
3525         }
3526         outSISIDXREG(SISCR, 0x31, cr31);
3527
3528         if(ivideo->accel) sisfb_syncaccel(ivideo);
3529
3530         ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3531 }
3532
3533 /* Fix SR11 for 661 and later */
3534 #ifdef CONFIG_FB_SIS_315
3535 static void
3536 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3537 {
3538     u8  tmpreg;
3539
3540     if(ivideo->chip >= SIS_661) {
3541        inSISIDXREG(SISSR,0x11,tmpreg);
3542        if(tmpreg & 0x20) {
3543           inSISIDXREG(SISSR,0x3e,tmpreg);
3544           tmpreg = (tmpreg + 1) & 0xff;
3545           outSISIDXREG(SISSR,0x3e,tmpreg);
3546           inSISIDXREG(SISSR,0x11,tmpreg);
3547        }
3548        if(tmpreg & 0xf0) {
3549           andSISIDXREG(SISSR,0x11,0x0f);
3550        }
3551     }
3552 }
3553 #endif
3554
3555 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3556 {
3557    if(val > 32) val = 32;
3558    if(val < -32) val = -32;
3559    ivideo->tvxpos = val;
3560
3561    if(ivideo->sisfblocked) return;
3562    if(!ivideo->modechanged) return;
3563
3564    if(ivideo->currentvbflags & CRT2_TV) {
3565
3566       if(ivideo->vbflags & VB_CHRONTEL) {
3567
3568          int x = ivideo->tvx;
3569
3570          switch(ivideo->chronteltype) {
3571          case 1:
3572              x += val;
3573              if(x < 0) x = 0;
3574              outSISIDXREG(SISSR,0x05,0x86);
3575              SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3576              SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3577              break;
3578          case 2:
3579              /* Not supported by hardware */
3580              break;
3581          }
3582
3583       } else if(ivideo->vbflags & VB_SISBRIDGE) {
3584
3585          u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3586          unsigned short temp;
3587
3588          p2_1f = ivideo->p2_1f;
3589          p2_20 = ivideo->p2_20;
3590          p2_2b = ivideo->p2_2b;
3591          p2_42 = ivideo->p2_42;
3592          p2_43 = ivideo->p2_43;
3593
3594          temp = p2_1f | ((p2_20 & 0xf0) << 4);
3595          temp += (val * 2);
3596          p2_1f = temp & 0xff;
3597          p2_20 = (temp & 0xf00) >> 4;
3598          p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3599          temp = p2_43 | ((p2_42 & 0xf0) << 4);
3600          temp += (val * 2);
3601          p2_43 = temp & 0xff;
3602          p2_42 = (temp & 0xf00) >> 4;
3603          outSISIDXREG(SISPART2,0x1f,p2_1f);
3604          setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3605          setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3606          setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3607          outSISIDXREG(SISPART2,0x43,p2_43);
3608       }
3609    }
3610 }
3611
3612 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3613 {
3614    if(val > 32) val = 32;
3615    if(val < -32) val = -32;
3616    ivideo->tvypos = val;
3617
3618    if(ivideo->sisfblocked) return;
3619    if(!ivideo->modechanged) return;
3620
3621    if(ivideo->currentvbflags & CRT2_TV) {
3622
3623       if(ivideo->vbflags & VB_CHRONTEL) {
3624
3625          int y = ivideo->tvy;
3626
3627          switch(ivideo->chronteltype) {
3628          case 1:
3629             y -= val;
3630             if(y < 0) y = 0;
3631             outSISIDXREG(SISSR,0x05,0x86);
3632             SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3633             SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3634             break;
3635          case 2:
3636             /* Not supported by hardware */
3637             break;
3638          }
3639
3640       } else if(ivideo->vbflags & VB_SISBRIDGE) {
3641
3642          char p2_01, p2_02;
3643          val /= 2;
3644          p2_01 = ivideo->p2_01;
3645          p2_02 = ivideo->p2_02;
3646
3647          p2_01 += val;
3648          p2_02 += val;
3649          while((p2_01 <= 0) || (p2_02 <= 0)) {
3650             p2_01 += 2;
3651             p2_02 += 2;
3652          }
3653          outSISIDXREG(SISPART2,0x01,p2_01);
3654          outSISIDXREG(SISPART2,0x02,p2_02);
3655       }
3656    }
3657 }
3658
3659 static void
3660 sisfb_post_setmode(struct sis_video_info *ivideo)
3661 {
3662         BOOLEAN crt1isoff = FALSE;
3663         BOOLEAN doit = TRUE;
3664 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3665         u8 reg;
3666 #endif
3667 #ifdef CONFIG_FB_SIS_315
3668         u8 reg1;
3669 #endif
3670
3671         outSISIDXREG(SISSR,0x05,0x86);
3672
3673 #ifdef CONFIG_FB_SIS_315
3674         sisfb_fixup_SR11(ivideo);
3675 #endif
3676
3677         /* Now we actually HAVE changed the display mode */
3678         ivideo->modechanged = 1;
3679
3680         /* We can't switch off CRT1 if bridge is in slave mode */
3681         if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3682                 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3683         } else ivideo->sisfb_crt1off = 0;
3684
3685 #ifdef CONFIG_FB_SIS_300
3686         if(ivideo->sisvga_engine == SIS_300_VGA) {
3687            if((ivideo->sisfb_crt1off) && (doit)) {
3688                 crt1isoff = TRUE;
3689                 reg = 0x00;
3690            } else {
3691                 crt1isoff = FALSE;
3692                 reg = 0x80;
3693            }
3694            setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3695         }
3696 #endif
3697 #ifdef CONFIG_FB_SIS_315
3698         if(ivideo->sisvga_engine == SIS_315_VGA) {
3699            if((ivideo->sisfb_crt1off) && (doit)) {
3700                 crt1isoff = TRUE;
3701                 reg  = 0x40;
3702                 reg1 = 0xc0;
3703            } else {
3704                 crt1isoff = FALSE;
3705                 reg  = 0x00;
3706                 reg1 = 0x00;
3707
3708            }
3709            setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3710            setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3711         }
3712 #endif
3713
3714         if(crt1isoff) {
3715            ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3716            ivideo->currentvbflags |= VB_SINGLE_MODE;
3717         } else {
3718            ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3719            if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3720                 ivideo->currentvbflags |= VB_MIRROR_MODE;
3721            } else {
3722                 ivideo->currentvbflags |= VB_SINGLE_MODE;
3723            }
3724         }
3725
3726         andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3727
3728         if(ivideo->currentvbflags & CRT2_TV) {
3729            if(ivideo->vbflags & VB_SISBRIDGE) {
3730               inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3731               inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3732               inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3733               inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3734               inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3735               inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3736               inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3737            } else if(ivideo->vbflags & VB_CHRONTEL) {
3738               if(ivideo->chronteltype == 1) {
3739                  ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3740                  ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3741                  ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3742                  ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3743               }
3744            }
3745         }
3746
3747         if(ivideo->tvxpos) {
3748            sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3749         }
3750         if(ivideo->tvypos) {
3751            sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3752         }
3753
3754         if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) {  /* Set filter for SiS301 */
3755
3756                 unsigned char filter_tb = 0;
3757
3758                 switch (ivideo->video_width) {
3759                    case 320:
3760                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3761                         break;
3762                    case 640:
3763                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3764                         break;
3765                    case 720:
3766                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3767                         break;
3768                    case 400:
3769                    case 800:
3770                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3771                         break;
3772                    default:
3773                         ivideo->sisfb_filter = -1;
3774                         break;
3775                 }
3776
3777                 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3778
3779                 if(ivideo->vbflags & TV_NTSC) {
3780
3781                         andSISIDXREG(SISPART2, 0x3a, 0x1f);
3782
3783                         if (ivideo->vbflags & TV_SVIDEO) {
3784
3785                                 andSISIDXREG(SISPART2, 0x30, 0xdf);
3786
3787                         } else if (ivideo->vbflags & TV_AVIDEO) {
3788
3789                                 orSISIDXREG(SISPART2, 0x30, 0x20);
3790
3791                                 switch (ivideo->video_width) {
3792                                 case 640:
3793                                         outSISIDXREG(SISPART2, 0x35, 0xEB);
3794                                         outSISIDXREG(SISPART2, 0x36, 0x04);
3795                                         outSISIDXREG(SISPART2, 0x37, 0x25);
3796                                         outSISIDXREG(SISPART2, 0x38, 0x18);
3797                                         break;
3798                                 case 720:
3799                                         outSISIDXREG(SISPART2, 0x35, 0xEE);
3800                                         outSISIDXREG(SISPART2, 0x36, 0x0C);
3801                                         outSISIDXREG(SISPART2, 0x37, 0x22);
3802                                         outSISIDXREG(SISPART2, 0x38, 0x08);
3803                                         break;
3804                                 case 400:
3805                                 case 800:
3806                                         outSISIDXREG(SISPART2, 0x35, 0xEB);
3807                                         outSISIDXREG(SISPART2, 0x36, 0x15);
3808                                         outSISIDXREG(SISPART2, 0x37, 0x25);
3809                                         outSISIDXREG(SISPART2, 0x38, 0xF6);
3810                                         break;
3811                                 }
3812                         }
3813
3814                 } else if(ivideo->vbflags & TV_PAL) {
3815
3816                         andSISIDXREG(SISPART2, 0x3A, 0x1F);
3817
3818                         if (ivideo->vbflags & TV_SVIDEO) {
3819
3820                                 andSISIDXREG(SISPART2, 0x30, 0xDF);
3821
3822                         } else if (ivideo->vbflags & TV_AVIDEO) {
3823
3824                                 orSISIDXREG(SISPART2, 0x30, 0x20);
3825
3826                                 switch (ivideo->video_width) {
3827                                 case 640:
3828                                         outSISIDXREG(SISPART2, 0x35, 0xF1);
3829                                         outSISIDXREG(SISPART2, 0x36, 0xF7);
3830                                         outSISIDXREG(SISPART2, 0x37, 0x1F);
3831                                         outSISIDXREG(SISPART2, 0x38, 0x32);
3832                                         break;
3833                                 case 720:
3834                                         outSISIDXREG(SISPART2, 0x35, 0xF3);
3835                                         outSISIDXREG(SISPART2, 0x36, 0x00);
3836                                         outSISIDXREG(SISPART2, 0x37, 0x1D);
3837                                         outSISIDXREG(SISPART2, 0x38, 0x20);
3838                                         break;
3839                                 case 400:
3840                                 case 800:
3841                                         outSISIDXREG(SISPART2, 0x35, 0xFC);
3842                                         outSISIDXREG(SISPART2, 0x36, 0xFB);
3843                                         outSISIDXREG(SISPART2, 0x37, 0x14);
3844                                         outSISIDXREG(SISPART2, 0x38, 0x2A);
3845                                         break;
3846                                 }
3847                         }
3848                 }
3849
3850                 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3851                    outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3852                    outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3853                    outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3854                    outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3855                 }
3856           
3857         }
3858 }
3859
3860 #ifndef MODULE
3861 SISINITSTATIC int __init sisfb_setup(char *options)
3862 {
3863         char *this_opt;
3864         
3865         sisfb_setdefaultparms();
3866
3867         printk(KERN_DEBUG "sisfb: Options %s\n", options);
3868
3869         if(!options || !(*options)) {
3870                 return 0;
3871         }
3872
3873         while((this_opt = strsep(&options, ",")) != NULL) {
3874
3875                 if(!(*this_opt)) continue;
3876
3877                 if(!strnicmp(this_opt, "off", 3)) {
3878                         sisfb_off = 1;
3879                 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3880                         /* Need to check crt2 type first for fstn/dstn */
3881                         sisfb_search_crt2type(this_opt + 14);
3882                 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3883                         sisfb_search_tvstd(this_opt + 7);
3884                 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3885                         sisfb_search_tvstd(this_opt + 7);
3886                 } else if(!strnicmp(this_opt, "mode:", 5)) {
3887                         sisfb_search_mode(this_opt + 5, FALSE);
3888                 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3889                         sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3890 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3891                 } else if(!strnicmp(this_opt, "inverse", 7)) {
3892                         sisfb_inverse = 1;
3893                         /* fb_invert_cmaps(); */
3894                 } else if(!strnicmp(this_opt, "font:", 5)) {
3895                         if(strlen(this_opt + 5) < 40) {
3896                            strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3897                            sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3898                         }
3899 #endif
3900                 } else if(!strnicmp(this_opt, "rate:", 5)) {
3901                         sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3902                 } else if(!strnicmp(this_opt, "filter:", 7)) {
3903                         sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3904                 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3905                         sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3906                 } else if(!strnicmp(this_opt, "mem:",4)) {
3907                         sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3908                 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3909                         sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3910                 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3911                         sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3912                 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3913                         sisfb_accel = 0;
3914                 } else if(!strnicmp(this_opt, "accel", 5)) {
3915                         sisfb_accel = -1;
3916                 } else if(!strnicmp(this_opt, "noypan", 6)) {
3917                         sisfb_ypan = 0;
3918                 } else if(!strnicmp(this_opt, "ypan", 4)) {
3919                         sisfb_ypan = -1;
3920                 } else if(!strnicmp(this_opt, "nomax", 5)) {
3921                         sisfb_max = 0;
3922                 } else if(!strnicmp(this_opt, "max", 3)) {
3923                         sisfb_max = -1;
3924                 } else if(!strnicmp(this_opt, "userom:", 7)) {
3925                         sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3926                 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3927                         sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3928                 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3929                         sisfb_nocrt2rate = 1;
3930                 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3931                         unsigned long temp = 2;
3932                         temp = simple_strtoul(this_opt + 9, NULL, 0);
3933                         if((temp == 0) || (temp == 1)) {
3934                            sisfb_scalelcd = temp ^ 1;
3935                         }
3936                 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3937                         int temp = 0;
3938                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3939                         if((temp >= -32) && (temp <= 32)) {
3940                            sisfb_tvxposoffset = temp;
3941                         }
3942                 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3943                         int temp = 0;
3944                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3945                         if((temp >= -32) && (temp <= 32)) {
3946                            sisfb_tvyposoffset = temp;
3947                         }
3948                 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3949                         sisfb_search_specialtiming(this_opt + 14);
3950                 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3951                         int temp = 4;
3952                         temp = simple_strtoul(this_opt + 7, NULL, 0);
3953                         if((temp >= 0) && (temp <= 3)) {
3954                            sisfb_lvdshl = temp;
3955                         }
3956                 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3957                         sisfb_search_mode(this_opt, TRUE);
3958 #if !defined(__i386__) && !defined(__x86_64__)
3959                 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3960                         sisfb_resetcard = 1;
3961                 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3962                         sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3963 #endif
3964                 } else {
3965                         printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3966                 }
3967
3968         }
3969
3970
3971
3972         return 0;
3973 }
3974 #endif
3975
3976 static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev)
3977 {
3978         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3979         USHORT pciid;
3980         int    romptr;
3981         UCHAR  *myrombase;
3982         u32    temp;
3983         SIS_IOTYPE1 *rom_base, *rom;
3984
3985         if(!(myrombase = vmalloc(65536))) return NULL;
3986
3987 #if defined(__i386__) || defined(__x86_64__)
3988
3989         for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
3990
3991             rom_base = ioremap(temp, 0x10000);
3992             if(!rom_base) continue;
3993
3994             if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3995                iounmap(rom_base);
3996                continue;
3997             }
3998
3999             romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4000             if(romptr > (0x10000 - 8)) {
4001                iounmap(rom_base);
4002                continue;
4003             }
4004
4005             rom = rom_base + romptr;
4006
4007             if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4008                (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
4009                iounmap(rom_base);
4010                continue;
4011             }
4012
4013             pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4014             if(pciid != 0x1039) {
4015                iounmap(rom_base);
4016                continue;
4017             }
4018
4019             pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4020             if(pciid == ivideo->chip_id) {
4021                memcpy_fromio(myrombase, rom_base, 65536);
4022                iounmap(rom_base);
4023                return myrombase;
4024             }
4025
4026             iounmap(rom_base);
4027         }
4028
4029 #else
4030
4031         pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4032         pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4033                         (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4034
4035         rom_base = ioremap(ivideo->video_base, 65536);
4036         if(rom_base) {
4037            if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4038               romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4039               if(romptr <= (0x10000 - 8)) {
4040                  rom = rom_base + romptr;
4041                  if((readb(rom)     == 'P') && (readb(rom + 1) == 'C') &&
4042                     (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4043                     pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4044                     if(pciid == 0x1039) {
4045                        pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4046                        if(pciid == ivideo->chip_id) {
4047                           memcpy_fromio(myrombase, rom_base, 65536);
4048                           iounmap(rom_base);
4049                           pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4050                           return myrombase;
4051                        }
4052                     }
4053                  }
4054               }
4055            }
4056            iounmap(rom_base);
4057         }
4058         pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4059
4060 #endif
4061
4062         vfree(myrombase);
4063         return NULL;
4064 }
4065
4066 #ifdef CONFIG_FB_SIS_300
4067 static int __devinit
4068 sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress)
4069 {
4070         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4071         int i, j;
4072         USHORT temp;
4073         UCHAR reg;
4074
4075         andSISIDXREG(SISSR,0x15,0xFB);
4076         orSISIDXREG(SISSR,0x15,0x04);
4077         outSISIDXREG(SISSR,0x13,0x00);
4078         outSISIDXREG(SISSR,0x14,0xBF);
4079
4080         for(i=0; i<2; i++) {
4081            temp = 0x1234;
4082            for(j=0; j<4; j++) {
4083               writew(temp, FBAddress);
4084               if(readw(FBAddress) == temp) break;
4085               orSISIDXREG(SISSR,0x3c,0x01);
4086               inSISIDXREG(SISSR,0x05,reg);
4087               inSISIDXREG(SISSR,0x05,reg);
4088               andSISIDXREG(SISSR,0x3c,0xfe);
4089               inSISIDXREG(SISSR,0x05,reg);
4090               inSISIDXREG(SISSR,0x05,reg);
4091               temp++;
4092            }
4093         }
4094
4095         writel(0x01234567L, FBAddress);
4096         writel(0x456789ABL, (FBAddress+4));
4097         writel(0x89ABCDEFL, (FBAddress+8));
4098         writel(0xCDEF0123L, (FBAddress+12));
4099         inSISIDXREG(SISSR,0x3b,reg);
4100         if(reg & 0x01) {
4101            if(readl((FBAddress+12)) == 0xCDEF0123L) return(4);  /* Channel A 128bit */
4102         }
4103         if(readl((FBAddress+4)) == 0x456789ABL)     return(2);  /* Channel B 64bit */
4104         return(1);                                              /* 32bit */
4105 }
4106
4107 static void __devinit
4108 sisfb_setramsize300(struct pci_dev *pdev)
4109 {
4110         struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
4111         SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4112         SIS_IOTYPE1 *Addr;
4113         USHORT  sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4114         int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4115         int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4116         int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4117         const   USHORT SiS_DRAMType[17][5] = {
4118                         {0x0C,0x0A,0x02,0x40,0x39},
4119                         {0x0D,0x0A,0x01,0x40,0x48},
4120                         {0x0C,0x09,0x02,0x20,0x35},
4121                         {0x0D,0x09,0x01,0x20,0x44},
4122                         {0x0C,0x08,0x02,0x10,0x31},
4123                         {0x0D,0x08,0x01,0x10,0x40},
4124                         {0x0C,0x0A,0x01,0x20,0x34},
4125                         {0x0C,0x09,0x01,0x08,0x32},
4126                         {0x0B,0x08,0x02,0x08,0x21},
4127                         {0x0C,0x08,0x01,0x08,0x30},
4128                         {0x0A,0x08,0x02,0x04,0x11},
4129                         {0x0B,0x0A,0x01,0x10,0x28},
4130                         {0x09,0x08,0x02,0x02,0x01},
4131                         {0x0B,0x09,0x01,0x08,0x24},
4132                         {0x0B,0x08,0x01,0x04,0x20},
4133                         {0x0A,0x08,0x01,0x02,0x10},
4134                         {0x09,0x08,0x01,0x01,0x00}
4135                 };
4136
4137         buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4138
4139         MB2Bank = 16;
4140         Done = 0;
4141         for(i = 6; i >= 0; i--) {
4142            if(Done) break;
4143            PseudoRankCapacity = 1 << i;
4144            for(j = 4; j >= 1; j--) {
4145               if(Done) break;
4146               PseudoTotalCapacity = PseudoRankCapacity * j;
4147               PseudoAdrPinCount = 15 - j;
4148               if(PseudoTotalCapacity <= 64) {
4149                  for(k = 0; k <= 16; k++) {
4150                     if(Done) break;
4151                     RankCapacity = buswidth * SiS_DRAMType[k][3];
4152                     AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4153                     if(RankCapacity == PseudoRankCapacity)
4154                        if(AdrPinCount <= PseudoAdrPinCount) {
4155                           if(j == 3) {             /* Rank No */
4156                              BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4157                              BankNumMid  = RankCapacity * MB2Bank * 1 - 1;
4158                           } else {
4159                              BankNumHigh = RankCapacity * MB2Bank * j - 1;
4160                              BankNumMid  = RankCapacity * MB2Bank * j / 2 - 1;
4161                           }
4162                           PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4163                           PhysicalAdrHigh = BankNumHigh;
4164                           PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4165                           PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4166                           /* Write data */
4167                           andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4168                           orSISIDXREG(SISSR,0x15,0x04);  /* Test */
4169                           TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4170                           sr13 = SiS_DRAMType[k][4];
4171                           if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80;
4172                           if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40;
4173                           if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00;
4174                           outSISIDXREG(SISSR,0x13,sr13);
4175                           outSISIDXREG(SISSR,0x14,sr14);
4176                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4177                           /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4178                           writew(((USHORT)PhysicalAdrHigh), Addr);
4179                           Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4180                           /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4181                           writew(((USHORT)BankNumMid), Addr);
4182                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4183                           /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4184                           writew(((USHORT)PhysicalAdrHalfPage), Addr);
4185                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4186                           /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4187                           writew(((USHORT)PhysicalAdrOtherPage), Addr);
4188                           /* Read data */
4189                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4190                           data = readw(Addr); /* *((USHORT *)(Addr)); */
4191                           if(data == PhysicalAdrHigh) Done = 1;
4192                        }  /* if */
4193                  }  /* for k */
4194               }  /* if */
4195            }  /* for j */
4196         }  /* for i */
4197 }
4198
4199 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4200 {
4201         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4202         u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4203         u16 index, rindex, memtype = 0;
4204
4205         outSISIDXREG(SISSR,0x05,0x86);
4206
4207         if(ivideo->sishw_ext.UseROM) {
4208            if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4209               memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4210            } else {
4211               inSISIDXREG(SISSR,0x3a,memtype);
4212            }
4213            memtype &= 0x07;
4214         }
4215
4216         if(ivideo->revision_id <= 0x13) {
4217            v1 = 0x44; v2 = 0x42; v3 = 0x80;
4218            v4 = 0x44; v5 = 0x42; v6 = 0x80;
4219         } else {
4220            v1 = 0x68; v2 = 0x43; v3 = 0x80;  /* Assume 125Mhz MCLK */
4221            v4 = 0x68; v5 = 0x43; v6 = 0x80;  /* Assume 125Mhz ECLK */
4222            if(ivideo->sishw_ext.UseROM) {
4223               index = memtype * 5;
4224               rindex = index + 0x54;
4225               v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4226               v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4227               v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4228               rindex = index + 0x7c;
4229               v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4230               v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4231               v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4232            }
4233         }
4234         outSISIDXREG(SISSR,0x28,v1);
4235         outSISIDXREG(SISSR,0x29,v2);
4236         outSISIDXREG(SISSR,0x2a,v3);
4237         outSISIDXREG(SISSR,0x2e,v4);
4238         outSISIDXREG(SISSR,0x2f,v5);
4239         outSISIDXREG(SISSR,0x30,v6);
4240         v1 = 0x10;
4241         if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4242         outSISIDXREG(SISSR,0x07,v1);       /* DAC speed */
4243         outSISIDXREG(SISSR,0x11,0x0f);     /* DDC, power save */
4244         v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4245         v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4246         if(ivideo->sishw_ext.UseROM) {
4247            memtype += 0xa5;
4248            v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4249            v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4250            v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4251            v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4252            v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4253            v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4254            v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4255            v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4256         }
4257         if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4258         outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4259         outSISIDXREG(SISSR,0x16,v2);
4260         outSISIDXREG(SISSR,0x17,v3);
4261         outSISIDXREG(SISSR,0x18,v4);
4262         outSISIDXREG(SISSR,0x19,v5);
4263         outSISIDXREG(SISSR,0x1a,v6);
4264         outSISIDXREG(SISSR,0x1b,v7);
4265         outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
4266         andSISIDXREG(SISSR,0x15,0xfb);
4267         orSISIDXREG(SISSR,0x15,0x04);
4268         if(ivideo->sishw_ext.UseROM) {
4269            if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4270               orSISIDXREG(SISSR,0x19,0x20);
4271            }
4272         }
4273         v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
4274         if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4275         outSISIDXREG(SISSR,0x1f,v1);
4276         outSISIDXREG(SISSR,0x20,0xa0);     /* linear & relocated io */
4277         v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4278         if(ivideo->sishw_ext.UseROM) {
4279            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4280            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4281            v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4282         }
4283         outSISIDXREG(SISSR,0x23,v1);
4284         outSISIDXREG(SISSR,0x24,v2);
4285         outSISIDXREG(SISSR,0x25,v3);
4286         outSISIDXREG(SISSR,0x21,0x84);
4287         outSISIDXREG(SISSR,0x22,0x00);
4288         outSISIDXREG(SISCR,0x37,0x00);
4289         orSISIDXREG(SISPART1,0x24,0x01);   /* unlock crt2 */
4290         outSISIDXREG(SISPART1,0x00,0x00);
4291         v1 = 0x40; v2 = 0x11;
4292         if(ivideo->sishw_ext.UseROM) {
4293            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4294            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4295         }
4296         outSISIDXREG(SISPART1,0x02,v1);
4297         if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4298         inSISIDXREG(SISPART4,0x00,reg);
4299         if((reg == 1) || (reg == 2)) {
4300            outSISIDXREG(SISCR,0x37,0x02);
4301            outSISIDXREG(SISPART2,0x00,0x1c);
4302            v4 = 0x00; v5 = 0x00; v6 = 0x10;
4303            if(ivideo->sishw_ext.UseROM) {
4304               v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4305               v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4306               v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4307            }
4308            outSISIDXREG(SISPART4,0x0d,v4);
4309            outSISIDXREG(SISPART4,0x0e,v5);
4310            outSISIDXREG(SISPART4,0x10,v6);
4311            outSISIDXREG(SISPART4,0x0f,0x3f);
4312            inSISIDXREG(SISPART4,0x01,reg);
4313            if(reg >= 0xb0) {
4314               inSISIDXREG(SISPART4,0x23,reg);
4315               reg &= 0x20;
4316               reg <<= 1;
4317               outSISIDXREG(SISPART4,0x23,reg);
4318            }
4319         } else {
4320            v2 &= ~0x10;
4321         }
4322         outSISIDXREG(SISSR,0x32,v2);
4323         andSISIDXREG(SISPART1,0x24,0xfe);  /* Lock CRT2 */
4324         inSISIDXREG(SISSR,0x16,reg);
4325         reg &= 0xc3;
4326         outSISIDXREG(SISCR,0x35,reg);
4327         outSISIDXREG(SISCR,0x83,0x00);
4328 #if !defined(__i386__) && !defined(__x86_64__)
4329         if(sisfb_videoram) {
4330            outSISIDXREG(SISSR,0x13,0x28);  /* ? */
4331            reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4332            outSISIDXREG(SISSR,0x14,reg);
4333         } else {
4334 #endif
4335            /* Need to map max FB size for finding out about RAM size */
4336            ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4337            if(ivideo->video_vbase) {
4338               sisfb_setramsize300(pdev);
4339               iounmap(ivideo->video_vbase);
4340            } else {
4341               printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4342               outSISIDXREG(SISSR,0x13,0x28);  /* ? */
4343               outSISIDXREG(SISSR,0x14,0x47);  /* 8MB, 64bit default */
4344            }
4345 #if !defined(__i386__) && !defined(__x86_64__)
4346         }
4347 #endif
4348         if(ivideo->sishw_ext.UseROM) {
4349            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4350            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4351         } else {
4352            inSISIDXREG(SISSR,0x3a,reg);
4353            if((reg & 0x30) == 0x30) {
4354               v1 = 0x04; /* PCI */
4355               v2 = 0x92;
4356            } else {
4357               v1 = 0x14; /* AGP */
4358               v2 = 0xb2;
4359            }
4360         }
4361         outSISIDXREG(SISSR,0x21,v1);
4362         outSISIDXREG(SISSR,0x22,v2);
4363 }
4364 #endif
4365
4366 #ifdef CONFIG_FB_SIS_315
4367 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4368 {
4369 #ifdef YET_TO_BE_DONE
4370         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4371         u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4372         u16 index, rindex, memtype = 0;
4373         u32 reg1_32, reg2_32, reg3_32;
4374         int i;
4375
4376         /* Unlock */
4377         /* outSISIDXREG(0x3c4,0x05,0x86); */
4378         outSISIDXREG(SISSR,0x05,0x86);
4379
4380         /* Enable relocated i/o ports */
4381         /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4382         setSISIDXREG(SISSR,0x20,~0x10,0x20);
4383
4384         /* Clear regs */
4385         for(i = 0; i < 0x22; i++) {
4386            outSISIDXREG(SISSR,(0x06 + i),0x00);
4387         }
4388         v1 = 0x0d;
4389         if( is 330) v1 = 0x0b;
4390         for(i = 0; i < v1; i++) {
4391            outSISIDXREG(SISSR,(0x31 + i),0x00);
4392         }
4393         for(i = 0; i < 0x10; i++) {
4394            outSISIDXREG(SISCR,(0x30 + i),0x00);
4395         }
4396
4397         /* Reset clocks */
4398         reg = inSISREG(SISMISCR);
4399         outSISIDXREG(SISSR,0x28,0x81);
4400         outSISIDXREG(SISSR,0x2A,0x00);
4401         outSISIDXREG(SISSR,0x29,0xE1);
4402         outSISREG(SISMISCW,(reg | 0x0c));
4403         outSISIDXREG(SISSR,0x2B,0x81);
4404         outSISIDXREG(SISSR,0x2D,0x00);
4405         outSISIDXREG(SISSR,0x2C,0xE1);
4406         outSISIDXREG(SISSR,0x2E,0x81);
4407         outSISIDXREG(SISSR,0x30,0x00);
4408         outSISIDXREG(SISSR,0x2F,0xE1);
4409         SiS_DDC2Delay(....);
4410         outSISREG(SISMISCW,reg);
4411
4412         /* Get memory type */
4413         if(ivideo->sishw_ext.UseROM) {
4414            if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4415               memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4416            } else {
4417               inSISIDXREG(SISSR,0x3a,memtype);
4418            }
4419            memtype &= 0x03;
4420            if( is 330 ) {
4421               if(memtype <= 1) memtype = 0;
4422               else {
4423                  inSISIDXREG(SISCR,0x5F,reg);
4424                  reg &= 0x30;
4425                  switch(reg) {
4426                  case 0x00: memtype = 1; break;
4427                  case 0x10: memtype = 3; break;
4428                  case 0x20: memtype = 3; break;
4429                  default:   memtype = 2;
4430                  }
4431               }
4432            }
4433         }
4434
4435         /* Set clocks */
4436         v1 = 0x3b; v2 = 0x22; v3 = 0x01;  /* Assume 143Mhz MCLK */
4437         v4 = 0x5c; v5 = 0x23; v6 = 0x01;  /* Assume 166Mhz ECLK */
4438         if(ivideo->sishw_ext.UseROM) {
4439            index = memtype * 5;
4440            rindex = index + 0x54;
4441            v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4442            v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4443            v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4444            rindex = index + 0x68;
4445            v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4446            v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4447            v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4448         }
4449         outSISIDXREG(SISSR,0x28,v1);
4450         outSISIDXREG(SISSR,0x29,v2);
4451         outSISIDXREG(SISSR,0x2a,v3);
4452         if( is 330 ) {
4453            inSISIDXREG(SISSR,0x3a,reg);
4454            reg &= 0x03;
4455            if(reg >= 2) {
4456               ...
4457            }
4458         }
4459         outSISIDXREG(SISSR,0x2e,v4);
4460         outSISIDXREG(SISSR,0x2f,v5);
4461         outSISIDXREG(SISSR,0x30,v6);
4462
4463         /* End of comp with 330 */
4464
4465         v1 = 0x18;
4466         if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4467         outSISIDXREG(SISSR,0x07,v1);
4468         outSISIDXREG(SISSR,0x11,0x0f);
4469
4470         v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4471         v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4472         if(ivideo->sishw_ext.UseROM) {
4473            index = memtype + 0x7d;
4474            v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4475            v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4476            v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4477            v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4478            v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4479            v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4480            v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4481         }
4482         outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0x7d step 4) */
4483         outSISIDXREG(SISSR,0x16,v2);
4484         outSISIDXREG(SISSR,0x17,v3);
4485         outSISIDXREG(SISSR,0x18,v4);
4486         outSISIDXREG(SISSR,0x19,v5);
4487         outSISIDXREG(SISSR,0x1a,v6);
4488         outSISIDXREG(SISSR,0x1b,v7);
4489         outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
4490
4491         v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4492         if(ivideo->sishw_ext.UseROM) {
4493            index = memtype + 0xa2;
4494            v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4495            v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4496            v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4497            v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4498            v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4499         }
4500         outSISIDXREG(SISCR,0x40,v1);
4501         outSISIDXREG(SISCR,0x41,v2);
4502         outSISIDXREG(SISCR,0x42,v3);
4503         outSISIDXREG(SISCR,0x43,v4);
4504         outSISIDXREG(SISCR,0x44,v5);
4505
4506         if( is 330 ) {
4507
4508            v1 = 0x;
4509            if(ivideo->sishw_ext.UseROM) {
4510               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4511            }
4512            outSISIDXREG(SISCR,0x59,v1);
4513
4514            v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4515            v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4516            if(ivideo->sishw_ext.UseROM) {
4517               index = memtype + 0xbe;
4518               v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4519               v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4520               v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4521               v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4522               v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4523               v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4524               v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4525               v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4526            }
4527            outSISIDXREG(SISCR,0x68,v1);
4528            outSISIDXREG(SISCR,0x69,v2);
4529            outSISIDXREG(SISCR,0x6a,v3);
4530            outSISIDXREG(SISCR,0x6b,v4);
4531            outSISIDXREG(SISCR,0x6c,v5);
4532            outSISIDXREG(SISCR,0x6d,v6);
4533            outSISIDXREG(SISCR,0x6e,v7);
4534            outSISIDXREG(SISCR,0x6f,v8);
4535
4536            v1 = 0x20;
4537            inSISIDXREG(SISSR,0x3b,reg);
4538
4539            if(!(reg & 0x04)) {
4540               inSISIDXREG(SISCR,0x5F,reg);
4541               reg &= 0x30;
4542               if(reg) v1 = 0x23;
4543            }
4544            outSISIDXREG(SISCR,0x48,v1);
4545            outSISIDXREG(SISCR,0x4c,0x20);
4546
4547            xx= xxx();
4548            if(xx >= 1) {
4549               v1 = 0x;
4550               if(ivideo->sishw_ext.UseROM) {
4551                  v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4552               }
4553               outSISIDXREG(SISCR,0x59,v1);
4554            }
4555
4556
4557
4558         } else {
4559
4560            outSISIDXREG(SISCR,0x48,0x23);
4561
4562            andSISIDXREG(SISSR,0x16,0x0f);
4563            if(memtype <= 1) {
4564               orSISIDXREG(SISSR,0x16,0x80);
4565            } else {
4566               v1 = 0x0f;
4567               if(ivideo->sishw_ext.UseROM) {
4568                  v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4569               }
4570               if(!(v1 & 0x10)) v2 = 0xc0;
4571               else             v2 = 0xd0;
4572               orSISIDXREG(SISSR,0x16,v2);
4573               andSISIDXREG(SISSR,0x16,0x0f);
4574               if(!(v1 & 0x10)) v2 = 0x80;
4575               else             v2 = 0xA0;
4576               orSISIDXREG(SISSR,0x16,v2);
4577            }
4578
4579            if(memtype >= 2) {
4580               const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4581               const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4582               for(i = 0; i < 11; i++) {
4583                  outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4584               }
4585               outSISIDXREG(SISSR,0x3d,0x00);
4586               outSISIDXREG(SISSR,0x3d,0x04);
4587               SiS_DDC2Delay(0x200);
4588               v1 = inSISIDXREG(SISCR,0xEC);
4589               v2 = inSISIDXREG(SISCR,0xED);
4590               reg1_32 = (v2 << 8) | v1;
4591               outSISIDXREG(SISSR,0x3D,0x00);
4592               for(i = 0; i < 11; i++) {
4593                  outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4594               }
4595               outSISIDXREG(SISSR,0x3d,0x00);
4596               outSISIDXREG(SISSR,0x3d,0x04);
4597               SiS_DDC2Delay(0x200);
4598               v1 = inSISIDXREG(SISCR,0xEC);
4599               v2 = inSISIDXREG(SISCR,0xED);
4600               reg2_32 = (v2 << 8) | v1;
4601               outSISIDXREG(SISSR,0x3D,0x00);
4602               reg3_32 = reg2_32 << 1;
4603               reg2_32 >>= 1;
4604               reg3_32 += reg2_32;
4605               v1 = 0x40;
4606               if(reg3_32 > reg1_32) v1 = 0x10;
4607                  outSISIDXREG(SISCR,0x59,v1);
4608            }
4609
4610         }
4611
4612         v1 = 0x00;
4613         if(ivideo->sishw_ext.UseROM) {
4614            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4615         }
4616         outSISIDXREG(SISSR,0x1f,v1);
4617
4618         outSISIDXREG(SISSR,0x20,0x20);
4619
4620         v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4621         if(ivideo->sishw_ext.UseROM) {
4622            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4623            v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4624            v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4625         }
4626         outSISIDXREG(SISSR,0x23,v1);
4627         outSISIDXREG(SISSR,0x24,v2);
4628         outSISIDXREG(SISSR,0x25,v3);
4629
4630         outSISIDXREG(SISSR,0x21,0x84);
4631         outSISIDXREG(SISSR,0x22,0x00);
4632         outSISIDXREG(SISSR,0x27,0x1f);
4633
4634         v1 = 0x00; v2 = 0x00;
4635         if(ivideo->sishw_ext.UseROM) {
4636            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4637            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4638         }
4639         outSISIDXREG(SISSR,0x31,v1);
4640         outSISIDXREG(SISSR,0x33,v2);
4641
4642         v1 = 0x11;
4643         if(ivideo->sishw_ext.UseROM) {
4644            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4645         }
4646         v2 = inSISIDXREG(SISPART4,0x00);
4647         if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4648         outSISIDXREG(SISSR,0x32,v1);
4649
4650         /* AGP */
4651         pci_read_config_long(pdev, 0x50, &reg1_32);
4652         reg1_32 >>= 20;
4653         reg1_32 &= 0x0f;
4654         if(reg1_32 == 1) {
4655            v1 = 0xAA; v2 = 0x33;
4656            if(ivideo->sishw_ext.UseROM) {
4657               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4658               v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4659            }
4660         } else {
4661            v1 = 0x88; v2 = 0x03;
4662            if(ivideo->sishw_ext.UseROM) {
4663               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4664               v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4665            }
4666         }
4667         outSISIDXREG(SISCR,0x49,v1);
4668         outSISIDXREG(SISSR,0x25,v2);
4669
4670         v1 = inSISIDXREG(SISPART4,0x00);
4671         if((v1 == 1) || (v1 == 2)) {
4672            orSISIDXREG(SISPART1,0x2F,0x01);  /* Unlock CRT2 */
4673            outSISIDXREG(SISPART1,0x00,0x00);
4674            v1 = 0x00;
4675            if(ivideo->sishw_ext.UseROM) {
4676               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4677            }
4678            outSISIDXREG(SISPART1,0x02,v1);
4679            outSISIDXREG(SISPART1,0x2E,0x08);
4680            outSISIDXREG(SISPART2,0x00,0x1c);
4681            v1 = 0x40; v2 = 0x00; v3 = 0x80;
4682            if(ivideo->sishw_ext.UseROM) {
4683               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4684               v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4685               v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4686            }
4687            outSISIDXREG(SISPART4,0x0d,v1);
4688            outSISIDXREG(SISPART4,0x0e,v2);
4689            outSISIDXREG(SISPART4,0x10,v3);
4690            outSISIDXREG(SISPART4,0x0F,0x3F);
4691
4692            inSISIDXREG(SISPART4,0x01,reg);
4693            if(reg >= 0xb0) {
4694               inSISIDXREG(SISPART4,0x23,reg);
4695               reg &= 0x20;
4696               reg <<= 1;
4697               outSISIDXREG(SISPART4,0x23,reg);
4698            }
4699         }
4700         outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4701
4702         outSISIDXREG(SISCR,0x83,0x00);
4703         outSISIDXREG(SISCR,0x90,0x00);
4704         andSISIDXREG(SISSR,0x5B,0xDF);
4705         outSISIDXREG(SISVID,0x00,0x86);
4706         outSISIDXREG(SISVID,0x32,0x00);
4707         outSISIDXREG(SISVID,0x30,0x00);
4708         outSISIDXREG(SISVID,0x32,0x01);
4709         outSISIDXREG(SISVID,0x30,0x00);
4710         orSISIDXREG(SISCR,0x63,0x80);
4711         /* End of Init1 */
4712
4713         /* Set Mode 0x2e */
4714
4715         /* Ramsize */
4716         orSISIDXREG(SISSR,0x16,0x0f);
4717         orSISIDXREG(SISSR,0x18,0xA9);
4718         orSISIDXREG(SISSR,0x19,0xA0);
4719         orSISIDXREG(SISSR,0x1B,0x30);
4720         andSISIDXREG(SISSR,0x17,0xF8);
4721         orSISIDXREG(SISSR,0x19,0x03);
4722         andSIDIDXREG(SISSR,0x13,0x00);
4723
4724         /* Need to map max FB size for finding out about RAM size */
4725         ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000);
4726         if(ivideo->video_vbase) {
4727            /* Find out about bus width */
4728            if(memtype <= 1) {
4729               outSISIDXREG(SISSR,0x14,0x02);
4730               andSISIDXREG(SISSR,0x16,0x0F);
4731               orSISIDXREG(SISSR,0x16,0x80);
4732
4733               ...
4734
4735            } else {
4736
4737               ...
4738
4739            }
4740
4741            /* Find out about size */
4742
4743
4744            iounmap(ivideo->video_vbase);
4745         } else {
4746            printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4747            outSISIDXREG(SISSR,0x14,0x??);  /* 8MB, 64bit default */
4748         }
4749
4750         /* AGP (Missing: Checks for VIA and AMD hosts) */
4751         v1 = 0xA5; v2 = 0xFB;
4752         if(ivideo->sishw_ext.UseROM) {
4753            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4754            v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4755         }
4756         outSISIDXREG(SISSR,0x21,v1);
4757         outSISIDXREG(SISSR,0x22,v2);
4758
4759 #endif
4760         return;
4761 }
4762 #endif
4763
4764
4765 static int __devinit sisfb_probe(struct pci_dev *pdev,
4766                                  const struct pci_device_id *ent)
4767 {
4768         struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
4769         struct sis_video_info   *ivideo = NULL;
4770         struct fb_info          *sis_fb_info = NULL;
4771         u16 reg16;
4772         u8  reg;
4773         int sisvga_enabled = 0, i;
4774
4775         if(sisfb_off) return -ENXIO;
4776
4777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4778         sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4779         if(!sis_fb_info) return -ENOMEM;
4780 #else
4781         sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4782         if(!sis_fb_info) return -ENOMEM;
4783         memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4784         sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4785 #endif
4786
4787         ivideo = (struct sis_video_info *)sis_fb_info->par;
4788         ivideo->memyselfandi = sis_fb_info;
4789
4790         if(card_list == NULL) {
4791            ivideo->cardnumber = 0;
4792         } else {
4793            struct sis_video_info *countvideo = card_list;
4794            ivideo->cardnumber = 1;
4795            while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4796         }
4797
4798         strncpy(ivideo->myid, chipinfo->chip_name, 30);
4799
4800         ivideo->warncount = 0;
4801         ivideo->chip_id = pdev->device;
4802         pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4803         ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4804         pci_read_config_word(pdev, PCI_COMMAND, &reg16);
4805         sisvga_enabled = reg16 & 0x01;
4806         ivideo->pcibus = pdev->bus->number;
4807         ivideo->pcislot = PCI_SLOT(pdev->devfn);
4808         ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4809         ivideo->subsysvendor = pdev->subsystem_vendor;
4810         ivideo->subsysdevice = pdev->subsystem_device;
4811
4812 #ifndef MODULE
4813         if(sisfb_mode_idx == -1) {
4814                 sisfb_get_vga_mode_from_kernel();
4815         }
4816 #endif
4817
4818         ivideo->chip = chipinfo->chip;
4819         ivideo->sisvga_engine = chipinfo->vgaengine;
4820         ivideo->hwcursor_size = chipinfo->hwcursor_size;
4821         ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4822         ivideo->mni = chipinfo->mni;
4823
4824         ivideo->detectedpdc  = 0xff;
4825         ivideo->detectedpdca = 0xff;
4826         ivideo->detectedlcda = 0xff;
4827
4828         ivideo->sisfb_thismonitor.datavalid = FALSE;
4829
4830         ivideo->sisfb_parm_mem = sisfb_parm_mem;
4831         ivideo->sisfb_accel = sisfb_accel;
4832         ivideo->sisfb_ypan = sisfb_ypan;
4833         ivideo->sisfb_max = sisfb_max;
4834         ivideo->sisfb_userom = sisfb_userom;
4835         ivideo->sisfb_useoem = sisfb_useoem;
4836         ivideo->sisfb_mode_idx = sisfb_mode_idx;
4837         ivideo->sisfb_parm_rate = sisfb_parm_rate;
4838         ivideo->sisfb_crt1off = sisfb_crt1off;
4839         ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4840         ivideo->sisfb_crt2type = sisfb_crt2type;
4841         ivideo->sisfb_crt2flags = sisfb_crt2flags;
4842         /* pdc(a), scalelcd, special timing, lvdshl handled below */
4843         ivideo->sisfb_dstn = sisfb_dstn;
4844         ivideo->sisfb_fstn = sisfb_fstn;
4845         ivideo->sisfb_tvplug = sisfb_tvplug;
4846         ivideo->sisfb_tvstd = sisfb_tvstd;
4847         ivideo->tvxpos = sisfb_tvxposoffset;
4848         ivideo->tvypos = sisfb_tvyposoffset;
4849         ivideo->sisfb_filter = sisfb_filter;
4850         ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4851 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4852         ivideo->sisfb_inverse = sisfb_inverse;
4853 #endif
4854
4855         ivideo->refresh_rate = 0;
4856         if(ivideo->sisfb_parm_rate != -1) {
4857            ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4858         }
4859
4860         ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4861         ivideo->SiS_Pr.CenterScreen = -1;
4862         ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4863         ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4864
4865         ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4866         ivideo->SiS_Pr.SiS_CHOverScan = -1;
4867         ivideo->SiS_Pr.SiS_ChSW = FALSE;
4868         ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4869         ivideo->SiS_Pr.HaveEMI = FALSE;
4870         ivideo->SiS_Pr.HaveEMILCD = FALSE;
4871         ivideo->SiS_Pr.OverruleEMI = FALSE;
4872         ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4873         ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4874         ivideo->SiS_Pr.PDC  = -1;
4875         ivideo->SiS_Pr.PDCA = -1;
4876 #ifdef CONFIG_FB_SIS_315
4877         if(ivideo->chip >= SIS_330) {
4878            ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4879            if(ivideo->chip >= SIS_661) {
4880               ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4881            }
4882         }
4883 #endif
4884
4885         memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4886
4887         pci_set_drvdata(pdev, ivideo);
4888
4889         /* Patch special cases */
4890         if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4891                 switch(ivideo->nbridge->device) {
4892 #ifdef CONFIG_FB_SIS_300
4893                 case PCI_DEVICE_ID_SI_730:
4894                         ivideo->chip = SIS_730;
4895                         strcpy(ivideo->myid, "SiS 730");
4896                         break;
4897 #endif
4898 #ifdef CONFIG_FB_SIS_315
4899                 case PCI_DEVICE_ID_SI_651:
4900                         /* ivideo->chip is ok */
4901                         strcpy(ivideo->myid, "SiS 651");
4902                         break;
4903                 case PCI_DEVICE_ID_SI_740:
4904                         ivideo->chip = SIS_740;
4905                         strcpy(ivideo->myid, "SiS 740");
4906                         break;
4907                 case PCI_DEVICE_ID_SI_661:
4908                         ivideo->chip = SIS_661;
4909                         strcpy(ivideo->myid, "SiS 661");
4910                         break;
4911                 case PCI_DEVICE_ID_SI_741:
4912                         ivideo->chip = SIS_741;
4913                         strcpy(ivideo->myid, "SiS 741");
4914                         break;
4915                 case PCI_DEVICE_ID_SI_760:
4916                         ivideo->chip = SIS_760;
4917                         strcpy(ivideo->myid, "SiS 760");
4918                         break;
4919 #endif
4920                 }
4921         }
4922
4923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4924         strcpy(sis_fb_info->modename, ivideo->myid);
4925 #endif
4926
4927         ivideo->sishw_ext.jChipType = ivideo->chip;
4928
4929 #ifdef CONFIG_FB_SIS_315
4930         if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4931            (ivideo->sishw_ext.jChipType == SIS_315)) {
4932                 ivideo->sishw_ext.jChipType = SIS_315H;
4933         }
4934 #endif
4935
4936         ivideo->video_base = pci_resource_start(pdev, 0);
4937         ivideo->mmio_base  = pci_resource_start(pdev, 1);
4938         ivideo->mmio_size  = pci_resource_len(pdev, 1);
4939         ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4940         ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4941
4942         if(!sisvga_enabled) {
4943                 if(pci_enable_device(pdev)) {
4944                         pci_set_drvdata(pdev, NULL);
4945                         kfree(sis_fb_info);
4946                         return -EIO;
4947                 }
4948         }
4949
4950         SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4951
4952 #ifdef CONFIG_FB_SIS_300
4953         /* Find PCI systems for Chrontel/GPIO communication setup */
4954         if(ivideo->chip == SIS_630) {
4955            i=0;
4956            do {
4957               if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4958                  mychswtable[i].subsysCard   == ivideo->subsysdevice) {
4959                  ivideo->SiS_Pr.SiS_ChSW = TRUE;
4960                  printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4961                         mychswtable[i].vendorName, mychswtable[i].cardName);
4962                  break;
4963               }
4964               i++;
4965            } while(mychswtable[i].subsysVendor != 0);
4966         }
4967 #endif
4968
4969         outSISIDXREG(SISSR, 0x05, 0x86);
4970
4971         if( (!sisvga_enabled)
4972 #if !defined(__i386__) && !defined(__x86_64__)
4973                               || (sisfb_resetcard)
4974 #endif
4975                                                    ) {
4976                 for(i = 0x30; i <= 0x3f; i++) {
4977                         outSISIDXREG(SISCR,i,0x00);
4978                 }
4979         }
4980
4981         /* Find out about current video mode */
4982         ivideo->modeprechange = 0x03;
4983         inSISIDXREG(SISCR,0x34,reg);
4984         if(reg & 0x7f) {
4985                 ivideo->modeprechange = reg & 0x7f;
4986         } else if(sisvga_enabled) {
4987 #if defined(__i386__) || defined(__x86_64__)
4988                 unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000);
4989                 if(tt) {
4990                         ivideo->modeprechange = readb(tt + 0x449);
4991                         iounmap(tt);
4992                 }
4993 #endif
4994         }
4995
4996 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4997 #ifdef MODULE
4998         if((reg & 0x80) && (reg != 0xff)) {
4999            if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
5000               printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
5001               pci_set_drvdata(pdev, NULL);
5002               kfree(sis_fb_info);
5003               return -EBUSY;
5004            }
5005         }
5006 #endif  
5007 #endif
5008
5009         ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
5010 #ifdef CONFIG_FB_SIS_300
5011         if(ivideo->sisvga_engine == SIS_300_VGA) {
5012            if(ivideo->chip != SIS_300) {
5013               inSISIDXREG(SISSR, 0x1a, reg);
5014               if(!(reg & 0x10)) {
5015                  ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
5016               }
5017            }
5018         }
5019 #endif
5020
5021         ivideo->bios_abase = NULL;
5022         if(ivideo->sisfb_userom) {
5023             ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5024             ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;
5025             if(ivideo->sishw_ext.pjVirtualRomBase) {
5026                 printk(KERN_INFO "sisfb: Video ROM found and copied\n");
5027                 ivideo->sishw_ext.UseROM = TRUE;
5028             } else {
5029                 ivideo->sishw_ext.UseROM = FALSE;
5030                 printk(KERN_INFO "sisfb: Video ROM not found\n");
5031             }
5032         } else {
5033             ivideo->sishw_ext.pjVirtualRomBase = NULL;
5034             ivideo->sishw_ext.UseROM = FALSE;
5035             printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5036         }
5037
5038         /* Find systems for special custom timing */
5039         if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5040            int j;
5041            unsigned char *biosver = NULL;
5042            unsigned char *biosdate = NULL;
5043            BOOLEAN footprint;
5044            u32 chksum = 0;
5045
5046            if(ivideo->sishw_ext.UseROM) {
5047               biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5048               biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5049               for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5050            }
5051
5052            i=0;
5053            do {
5054               if( (mycustomttable[i].chipID == ivideo->chip) &&
5055                   ((!strlen(mycustomttable[i].biosversion)) ||
5056                    (ivideo->sishw_ext.UseROM &&
5057                    (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5058                   ((!strlen(mycustomttable[i].biosdate)) ||
5059                    (ivideo->sishw_ext.UseROM &&
5060                    (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5061                   ((!mycustomttable[i].bioschksum) ||
5062                    (ivideo->sishw_ext.UseROM &&
5063                    (mycustomttable[i].bioschksum == chksum)))   &&
5064                   (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5065                   (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5066                  footprint = TRUE;
5067                  for(j = 0; j < 5; j++) {
5068                     if(mycustomttable[i].biosFootprintAddr[j]) {
5069                        if(ivideo->sishw_ext.UseROM) {
5070                           if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5071                                 mycustomttable[i].biosFootprintData[j]) {
5072                              footprint = FALSE;
5073                           }
5074                        } else footprint = FALSE;
5075                     }
5076                  }
5077                  if(footprint) {
5078                     ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5079                     printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5080                         mycustomttable[i].vendorName,
5081                         mycustomttable[i].cardName);
5082                     printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5083                         mycustomttable[i].optionName);
5084                     break;
5085                  }
5086               }
5087               i++;
5088            } while(mycustomttable[i].chipID);
5089         }
5090
5091 #ifdef CONFIG_FB_SIS_300
5092         if(ivideo->sisvga_engine == SIS_300_VGA) {
5093                 if( (!sisvga_enabled)
5094 #if !defined(__i386__) && !defined(__x86_64__)
5095                                       || (sisfb_resetcard)
5096 #endif
5097                                                            ) {
5098                         if(ivideo->chip == SIS_300) {
5099                                 sisfb_post_sis300(pdev);
5100                         }
5101                 }
5102         }
5103 #endif
5104
5105 #ifdef CONFIG_FB_SIS_315
5106         if(ivideo->sisvga_engine == SIS_315_VGA) {
5107                 if( (!sisvga_enabled)
5108 #if !defined(__i386__) && !defined(__x86_64__)
5109                                      || (sisfb_resetcard)
5110 #endif
5111                                                           ) {
5112                         if((ivideo->chip == SIS_315H)   ||
5113                            (ivideo->chip == SIS_315)    ||
5114                            (ivideo->chip == SIS_315PRO) ||
5115                            (ivideo->chip == SIS_330)) {
5116                                 sisfb_post_sis315330(pdev);
5117                         }
5118                 }
5119         }
5120 #endif
5121
5122         if(sisfb_get_dram_size(ivideo)) {
5123                 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5124                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5125                 pci_set_drvdata(pdev, NULL);
5126                 kfree(sis_fb_info);
5127                 return -ENODEV;
5128         }
5129
5130         if((ivideo->sisfb_mode_idx < 0) ||
5131            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5132                 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
5133                 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5134                 /* Enable 2D accelerator engine */
5135                 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5136         }
5137
5138         if(sisfb_pdc != 0xff) {
5139            if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5140            else                                     sisfb_pdc &= 0x1f;
5141            ivideo->SiS_Pr.PDC = sisfb_pdc;
5142         }
5143 #ifdef CONFIG_FB_SIS_315
5144         if(ivideo->sisvga_engine == SIS_315_VGA) {
5145            if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5146         }
5147 #endif
5148
5149         if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5150                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5151                 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5152                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5153                 pci_set_drvdata(pdev, NULL);
5154                 kfree(sis_fb_info);
5155                 return -ENODEV;
5156         }
5157
5158         if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5159                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5160                 release_mem_region(ivideo->video_base, ivideo->video_size);
5161                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5162                 pci_set_drvdata(pdev, NULL);
5163                 kfree(sis_fb_info);
5164                 return -ENODEV;
5165         }
5166
5167         ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5168         ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5169         if(!ivideo->video_vbase) {
5170                 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5171                 release_mem_region(ivideo->video_base, ivideo->video_size);
5172                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5173                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5174                 pci_set_drvdata(pdev, NULL);
5175                 kfree(sis_fb_info);
5176                 return -ENODEV;
5177         }
5178
5179         ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5180         if(!ivideo->mmio_vbase) {
5181                 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5182                 iounmap(ivideo->video_vbase);
5183                 release_mem_region(ivideo->video_base, ivideo->video_size);
5184                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5185                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5186                 pci_set_drvdata(pdev, NULL);
5187                 kfree(sis_fb_info);
5188                 return -ENODEV;
5189         }
5190
5191         printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5192                 ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024);
5193
5194         printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5195                 ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5196
5197         if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5198                 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5199         }
5200
5201         /* Used for clearing the screen only, therefore respect our mem limit */
5202         ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5203
5204         ivideo->mtrr = 0;
5205
5206         ivideo->vbflags = 0;
5207         ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5208         ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
5209         ivideo->defmodeidx    = DEFAULT_MODE;
5210
5211         ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5212
5213         if((ivideo->sisfb_mode_idx < 0) ||
5214            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5215
5216                 sisfb_sense_crt1(ivideo);
5217
5218                 sisfb_get_VB_type(ivideo);
5219
5220                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5221                         sisfb_detect_VB_connect(ivideo);
5222                 }
5223
5224                 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5225
5226                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5227                    if(ivideo->sisfb_crt2type != -1) {
5228                       if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5229                          ivideo->currentvbflags |= CRT2_LCD;
5230                       } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5231                          ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5232                       }
5233                    } else {
5234                       /* Chrontel 700x TV detection often unreliable, therefore use a
5235                        * different default order on such machines
5236                        */
5237                       if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5238                          if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
5239                          else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
5240                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5241                       } else {
5242                          if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
5243                          else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5244                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5245                       }
5246                    }
5247                 }
5248
5249                 if(ivideo->vbflags & CRT2_LCD) {
5250                    inSISIDXREG(SISCR, 0x36, reg);
5251                    reg &= 0x0f;
5252                    if(ivideo->sisvga_engine == SIS_300_VGA) {
5253                       ivideo->CRT2LCDType = sis300paneltype[reg];
5254                    } else if(ivideo->chip >= SIS_661) {
5255                       ivideo->CRT2LCDType = sis661paneltype[reg];
5256                    } else {
5257                       ivideo->CRT2LCDType = sis310paneltype[reg];
5258                       if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5259                          if((ivideo->CRT2LCDType != LCD_640x480_2) &&
5260                             (ivideo->CRT2LCDType != LCD_640x480_3)) {
5261                             ivideo->CRT2LCDType = LCD_320x480;
5262                          }
5263                       }
5264                    }
5265                    if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
5266                       /* For broken BIOSes: Assume 1024x768, RGB18 */
5267                       ivideo->CRT2LCDType = LCD_1024x768;
5268                       setSISIDXREG(SISCR,0x36,0xf0,0x02);
5269                       setSISIDXREG(SISCR,0x37,0xee,0x01);
5270                       printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
5271                    }
5272                    for(i = 0; i < SIS_LCD_NUMBER; i++) {
5273                       if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
5274                          ivideo->lcdxres = sis_lcd_data[i].xres;
5275                          ivideo->lcdyres = sis_lcd_data[i].yres;
5276                          ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5277                          break;
5278                       }
5279                    }
5280                    if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5281                         ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5282                    } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5283                         ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
5284                    }
5285                    printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5286                                 ivideo->lcdxres, ivideo->lcdyres);
5287                 }
5288
5289 #ifdef CONFIG_FB_SIS_300
5290                 /* Save the current PanelDelayCompensation if the LCD is currently used */
5291                 if(ivideo->sisvga_engine == SIS_300_VGA) {
5292                    if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5293                        int tmp;
5294                        inSISIDXREG(SISCR,0x30,tmp);
5295                        if(tmp & 0x20) {
5296                           /* Currently on LCD? If yes, read current pdc */
5297                           inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5298                           ivideo->detectedpdc &= 0x3c;
5299                           if(ivideo->SiS_Pr.PDC == -1) {
5300                              /* Let option override detection */
5301                              ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5302                           }
5303                           printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5304                                  ivideo->detectedpdc);
5305                        }
5306                        if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5307                           printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5308                                  ivideo->SiS_Pr.PDC);
5309                        }
5310                    }
5311                 }
5312 #endif
5313
5314 #ifdef CONFIG_FB_SIS_315
5315                 if(ivideo->sisvga_engine == SIS_315_VGA) {
5316
5317                    /* Try to find about LCDA */
5318                    if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5319                       int tmp;
5320                       inSISIDXREG(SISPART1,0x13,tmp);
5321                       if(tmp & 0x04) {
5322                          ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5323                          ivideo->detectedlcda = 0x03;
5324                       }
5325                    }
5326
5327                    /* Save PDC */
5328                    if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5329                       int tmp;
5330                       inSISIDXREG(SISCR,0x30,tmp);
5331                       if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5332                          /* Currently on LCD? If yes, read current pdc */
5333                          u8 pdc;
5334                          inSISIDXREG(SISPART1,0x2D,pdc);
5335                          ivideo->detectedpdc  = (pdc & 0x0f) << 1;
5336                          ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5337                          inSISIDXREG(SISPART1,0x35,pdc);
5338                          ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5339                          inSISIDXREG(SISPART1,0x20,pdc);
5340                          ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5341                          if(ivideo->newrom) {
5342                             /* New ROM invalidates other PDC resp. */
5343                             if(ivideo->detectedlcda != 0xff) {
5344                                ivideo->detectedpdc = 0xff;
5345                             } else {
5346                                ivideo->detectedpdca = 0xff;
5347                             }
5348                          }
5349                          if(ivideo->SiS_Pr.PDC == -1) {
5350                             if(ivideo->detectedpdc != 0xff) {
5351                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5352                             }
5353                          }
5354                          if(ivideo->SiS_Pr.PDCA == -1) {
5355                             if(ivideo->detectedpdca != 0xff) {
5356                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5357                             }
5358                          }
5359                          if(ivideo->detectedpdc != 0xff) {
5360                             printk(KERN_INFO
5361                                  "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5362                                   ivideo->detectedpdc);
5363                          }
5364                          if(ivideo->detectedpdca != 0xff) {
5365                             printk(KERN_INFO
5366                                  "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5367                                   ivideo->detectedpdca);
5368                          }
5369                       }
5370
5371                       /* Save EMI */
5372                       if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5373                          inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5374                          inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5375                          inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5376                          inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5377                          ivideo->SiS_Pr.HaveEMI = TRUE;
5378                          if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5379                                 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5380                          }
5381                       }
5382                    }
5383
5384                    /* Let user override detected PDCs (all bridges) */
5385                    if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5386                       if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5387                          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5388                                  ivideo->SiS_Pr.PDC);
5389                       }
5390                       if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5391                          printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5392                                  ivideo->SiS_Pr.PDCA);
5393                       }
5394                    }
5395
5396                 }
5397 #endif
5398
5399                 if(!ivideo->sisfb_crt1off) {
5400                         sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5401                 } else {
5402                         if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5403                            (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5404                                 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5405                         }
5406                 }
5407
5408                 if(ivideo->sisfb_mode_idx >= 0) {
5409                         int bu = ivideo->sisfb_mode_idx;
5410                         ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5411                                         ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5412                         if(bu != ivideo->sisfb_mode_idx) {
5413                                 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5414                                         sisbios_mode[bu].xres,
5415                                         sisbios_mode[bu].yres,
5416                                         sisbios_mode[bu].bpp);
5417                         }
5418                 }
5419
5420                 if(ivideo->sisfb_mode_idx < 0) {
5421                         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5422                            case CRT2_LCD:
5423                                 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5424                                 break;
5425                            case CRT2_TV:
5426                                 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5427                                 break;
5428                            default:
5429                                 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5430                                 break;
5431                         }
5432                 }
5433
5434                 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5435
5436                 if(ivideo->refresh_rate != 0) {
5437                         sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5438                 }
5439
5440                 if(ivideo->rate_idx == 0) {
5441                         ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5442                         ivideo->refresh_rate = 60;
5443                 }
5444
5445                 if(ivideo->sisfb_thismonitor.datavalid) {
5446                         if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5447                                               ivideo->rate_idx, ivideo->refresh_rate)) {
5448                                 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5449                         }
5450                 }
5451
5452                 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5453                 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5454                 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5455
5456                 sisfb_set_vparms(ivideo);
5457                 
5458 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  
5459
5460                 /* ---------------- For 2.4: Now switch the mode ------------------ */          
5461                 
5462                 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5463                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5464                         ivideo->refresh_rate);
5465
5466                 sisfb_pre_setmode(ivideo);
5467
5468                 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5469                         printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5470                                                                         ivideo->mode_no);
5471                         iounmap(ivideo->video_vbase);
5472                         iounmap(ivideo->mmio_vbase);
5473                         release_mem_region(ivideo->video_base, ivideo->video_size);
5474                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5475                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5476                         pci_set_drvdata(pdev, NULL);
5477                         kfree(sis_fb_info);
5478                         return -EINVAL;
5479                 }
5480
5481                 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5482
5483                 sisfb_post_setmode(ivideo);
5484
5485                 /* Maximize regardless of sisfb_max at startup */
5486                 ivideo->default_var.yres_virtual = 32767;
5487
5488                 /* Force reset of x virtual in crtc_to_var */
5489                 ivideo->default_var.xres_virtual = 0;
5490
5491                 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5492
5493                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5494                 sisfb_set_pitch(ivideo);
5495
5496                 ivideo->accel = 0;
5497                 if(ivideo->sisfb_accel) {
5498                    ivideo->accel = -1;
5499                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5500                 }
5501                 sisfb_initaccel(ivideo);
5502                 
5503                 sis_fb_info->node  = -1;
5504                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5505                 sis_fb_info->fbops = &sisfb_ops;
5506                 sis_fb_info->disp  = &ivideo->sis_disp;
5507                 sis_fb_info->blank = &sisfb_blank;
5508                 sis_fb_info->switch_con = &sisfb_switch;
5509                 sis_fb_info->updatevar  = &sisfb_update_var;
5510                 sis_fb_info->changevar  = NULL;
5511                 strcpy(sis_fb_info->fontname, sisfb_fontname);
5512
5513                 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5514
5515 #else           /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5516
5517                 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5518                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5519                         ivideo->refresh_rate);
5520
5521                 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5522                 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5523                 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5524
5525                 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5526                 
5527                 ivideo->default_var.pixclock = (u32) (1000000000 /
5528                                 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5529                                                 ivideo->mode_no, ivideo->rate_idx));
5530                                                 
5531                 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5532                                 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5533                    if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5534                       ivideo->default_var.pixclock <<= 1;
5535                    }
5536                 }
5537
5538                 if(ivideo->sisfb_ypan) {
5539                    /* Maximize regardless of sisfb_max at startup */
5540                    ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5541                    if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5542                       ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5543                    }
5544                 }
5545
5546                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5547
5548                 ivideo->accel = 0;
5549                 if(ivideo->sisfb_accel) {
5550                    ivideo->accel = -1;
5551 #ifdef STUPID_ACCELF_TEXT_SHIT
5552                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5553 #endif
5554                 }
5555                 sisfb_initaccel(ivideo);
5556
5557 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5558                 sis_fb_info->flags = FBINFO_DEFAULT             |
5559                                      FBINFO_HWACCEL_YPAN        |
5560                                      FBINFO_HWACCEL_XPAN        |
5561                                      FBINFO_HWACCEL_COPYAREA    |
5562                                      FBINFO_HWACCEL_FILLRECT    |
5563                                      ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5564 #else
5565                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5566 #endif
5567                 sis_fb_info->var = ivideo->default_var;
5568                 sis_fb_info->fix = ivideo->sisfb_fix;
5569                 sis_fb_info->screen_base = ivideo->video_vbase;
5570                 sis_fb_info->fbops = &sisfb_ops;
5571
5572                 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5573                 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5574                 
5575                 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5576 #endif          /* 2.6 */
5577
5578                 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5579
5580 #ifdef CONFIG_MTRR
5581                 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5582                                         MTRR_TYPE_WRCOMB, 1);
5583                 if(!ivideo->mtrr) {
5584                         printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5585                 }
5586 #endif
5587
5588 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5589                 vc_resize_con(1, 1, 0);
5590 #endif
5591
5592                 if(register_framebuffer(sis_fb_info) < 0) {
5593                         printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5594                         iounmap(ivideo->video_vbase);
5595                         iounmap(ivideo->mmio_vbase);
5596                         release_mem_region(ivideo->video_base, ivideo->video_size);
5597                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5598                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5599                         pci_set_drvdata(pdev, NULL);
5600                         kfree(sis_fb_info);
5601                         return -EINVAL;
5602                 }
5603
5604                 ivideo->registered = 1;
5605
5606                 /* Enlist us */
5607                 ivideo->next = card_list;
5608                 card_list = ivideo;
5609
5610                 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5611                      ivideo->sisfb_accel ? "enabled" : "disabled",
5612                      ivideo->sisfb_ypan  ?
5613                         (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5614
5615
5616                 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5617 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5618                         GET_FB_IDX(sis_fb_info->node),
5619 #else
5620                         sis_fb_info->node,
5621 #endif
5622                         ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5623
5624                 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5625
5626         }       /* if mode = "none" */
5627
5628         return 0;
5629 }
5630
5631 /*****************************************************/
5632 /*                PCI DEVICE HANDLING                */
5633 /*****************************************************/
5634
5635 static void __devexit sisfb_remove(struct pci_dev *pdev)
5636 {
5637         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5638         struct fb_info        *sis_fb_info = ivideo->memyselfandi;
5639         int                   registered = ivideo->registered;
5640
5641         /* Unmap */
5642         iounmap(ivideo->video_vbase);
5643         iounmap(ivideo->mmio_vbase);
5644         vfree(ivideo->bios_abase);
5645
5646         /* Release mem regions */
5647         release_mem_region(ivideo->video_base, ivideo->video_size);
5648         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5649
5650 #ifdef CONFIG_MTRR
5651         /* Release MTRR region */
5652         if(ivideo->mtrr) {
5653                 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5654         }
5655 #endif
5656
5657         /* Unregister the framebuffer */
5658         if(ivideo->registered) {
5659                 unregister_framebuffer(sis_fb_info);
5660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5661                 framebuffer_release(sis_fb_info);
5662 #else
5663                 kfree(sis_fb_info);
5664 #endif
5665         }
5666
5667         pci_set_drvdata(pdev, NULL);
5668
5669         /* TODO: Restore the initial mode
5670          * This sounds easy but is as good as impossible
5671          * on many machines with SiS chip and video bridge
5672          * since text modes are always set up differently
5673          * from machine to machine. Depends on the type
5674          * of integration between chipset and bridge.
5675          */
5676         if(registered) {
5677            printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5678         }
5679 };
5680
5681 static struct pci_driver sisfb_driver = {
5682         .name           = "sisfb",
5683         .id_table       = sisfb_pci_table,
5684         .probe          = sisfb_probe,
5685         .remove         = __devexit_p(sisfb_remove)
5686 };
5687
5688 SISINITSTATIC int __init sisfb_init(void)
5689 {
5690 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5691 #ifndef MODULE
5692         char *options = NULL;
5693
5694         if(fb_get_options("sisfb", &options))
5695                 return -ENODEV;
5696         sisfb_setup(options);
5697 #endif
5698 #endif
5699         return(pci_register_driver(&sisfb_driver));
5700 }
5701
5702 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5703 #ifndef MODULE
5704 module_init(sisfb_init);
5705 #endif
5706 #endif
5707
5708 /*****************************************************/
5709 /*                      MODULE                       */
5710 /*****************************************************/
5711
5712 #ifdef MODULE
5713
5714 static char         *mode = NULL;
5715 static int          vesa = -1;
5716 static unsigned int rate = 0;
5717 static unsigned int crt1off = 1;
5718 static unsigned int mem = 0;
5719 static char         *forcecrt2type = NULL;
5720 static int          forcecrt1 = -1;
5721 static int          pdc = -1;
5722 static int          pdc1 = -1;
5723 static int          noaccel = -1;
5724 static int          noypan  = -1;
5725 static int          nomax = -1;
5726 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5727 static int          inverse = 0;
5728 #endif
5729 static int          userom = -1;
5730 static int          useoem = -1;
5731 static char         *tvstandard = NULL;
5732 static int          nocrt2rate = 0;
5733 static int          scalelcd = -1;
5734 static char         *specialtiming = NULL;
5735 static int          lvdshl = -1;
5736 static int          tvxposoffset = 0, tvyposoffset = 0;
5737 static int          filter = -1;
5738 #if !defined(__i386__) && !defined(__x86_64__)
5739 static int          resetcard = 0;
5740 static int          videoram = 0;
5741 #endif
5742
5743 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5744 MODULE_LICENSE("GPL");
5745 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5746
5747 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5748 MODULE_PARM(mem, "i");
5749 MODULE_PARM(noaccel, "i");
5750 MODULE_PARM(noypan, "i");
5751 MODULE_PARM(nomax, "i");
5752 MODULE_PARM(userom, "i");
5753 MODULE_PARM(useoem, "i");
5754 MODULE_PARM(mode, "s");
5755 MODULE_PARM(vesa, "i");
5756 MODULE_PARM(rate, "i");
5757 MODULE_PARM(forcecrt1, "i");
5758 MODULE_PARM(forcecrt2type, "s");
5759 MODULE_PARM(scalelcd, "i");
5760 MODULE_PARM(pdc, "i");
5761 MODULE_PARM(pdc1, "i");
5762 MODULE_PARM(specialtiming, "s");
5763 MODULE_PARM(lvdshl, "i");
5764 MODULE_PARM(tvstandard, "s");
5765 MODULE_PARM(tvxposoffset, "i");
5766 MODULE_PARM(tvyposoffset, "i");
5767 MODULE_PARM(filter, "i");
5768 MODULE_PARM(nocrt2rate, "i");
5769 MODULE_PARM(inverse, "i");
5770 #if !defined(__i386__) && !defined(__x86_64__)
5771 MODULE_PARM(resetcard, "i");
5772 MODULE_PARM(videoram, "i");
5773 #endif
5774 #endif
5775
5776 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5777 module_param(mem, int, 0);
5778 module_param(noaccel, int, 0);
5779 module_param(noypan, int, 0);
5780 module_param(nomax, int, 0);
5781 module_param(userom, int, 0);
5782 module_param(useoem, int, 0);
5783 module_param(mode, charp, 0);
5784 module_param(vesa, int, 0);
5785 module_param(rate, int, 0);
5786 module_param(forcecrt1, int, 0);
5787 module_param(forcecrt2type, charp, 0);
5788 module_param(scalelcd, int, 0);
5789 module_param(pdc, int, 0);
5790 module_param(pdc1, int, 0);
5791 module_param(specialtiming, charp, 0);
5792 module_param(lvdshl, int, 0);
5793 module_param(tvstandard, charp, 0);
5794 module_param(tvxposoffset, int, 0);
5795 module_param(tvyposoffset, int, 0);
5796 module_param(filter, int, 0);
5797 module_param(nocrt2rate, int, 0);
5798 #if !defined(__i386__) && !defined(__x86_64__)
5799 module_param(resetcard, int, 0);
5800 module_param(videoram, int, 0);
5801 #endif
5802 #endif
5803
5804 MODULE_PARM_DESC(mem,
5805         "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5806           "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5807           "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5808           "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5809           "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5810           "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5811           "for XFree86 4.x/X.org 6.7 and later.\n");
5812
5813 MODULE_PARM_DESC(noaccel,
5814         "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5815           "(default: 0)\n");
5816
5817 MODULE_PARM_DESC(noypan,
5818         "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5819           "will be performed by redrawing the screen. (default: 0)\n");
5820
5821 MODULE_PARM_DESC(nomax,
5822         "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5823           "memory for the virtual screen in order to optimize scrolling performance. If\n"
5824           "this is set to anything other than 0, sisfb will not do this and thereby \n"
5825           "enable the user to positively specify a virtual Y size of the screen using\n"
5826           "fbset. (default: 0)\n");
5827
5828 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5829 MODULE_PARM_DESC(mode,
5830         "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5831           "1024x768x16. Other formats supported include XxY-Depth and\n"
5832           "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5833           "number, it will be interpreted as a VESA mode number. (default: none if\n"
5834           "sisfb is a module; this leaves the console untouched and the driver will\n"
5835           "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5836           "is in the kernel)\n");
5837 MODULE_PARM_DESC(vesa,
5838         "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5839           "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5840           "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5841           "0x0103 if sisfb is in the kernel)\n");
5842 #endif
5843
5844 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5845 MODULE_PARM_DESC(mode,
5846        "\nSelects the desired default display mode in the format XxYxDepth,\n"
5847          "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5848          "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5849          "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5850
5851 MODULE_PARM_DESC(vesa,
5852        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5853          "0x117 (default: 0x0103)\n");
5854 #endif
5855
5856 MODULE_PARM_DESC(rate,
5857         "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5858           "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5859           "will be ignored (default: 60)\n");
5860
5861 MODULE_PARM_DESC(forcecrt1,
5862         "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5863           "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5864           "0=CRT1 OFF) (default: [autodetected])\n");
5865
5866 MODULE_PARM_DESC(forcecrt2type,
5867         "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5868           "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5869           "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5870           "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5871           "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5872           "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5873           "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5874           "depends on the very hardware in use. (default: [autodetected])\n");
5875
5876 MODULE_PARM_DESC(scalelcd,
5877         "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5878           "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5879           "show black bars around the image, TMDS panels will probably do the scaling\n"
5880           "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5881
5882 MODULE_PARM_DESC(pdc,
5883         "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5884           "should detect this correctly in most cases; however, sometimes this is not\n"
5885           "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5886           "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5887           "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5888           "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5889
5890 #ifdef CONFIG_FB_SIS_315
5891 MODULE_PARM_DESC(pdc1,
5892         "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5893           "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5894           "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5895           "implemented yet.\n");
5896 #endif
5897
5898 MODULE_PARM_DESC(specialtiming,
5899         "\nPlease refer to documentation for more information on this option.\n");
5900
5901 MODULE_PARM_DESC(lvdshl,
5902         "\nPlease refer to documentation for more information on this option.\n");
5903
5904 MODULE_PARM_DESC(tvstandard,
5905         "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5906           "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5907
5908 MODULE_PARM_DESC(tvxposoffset,
5909         "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5910           "Default: 0\n");
5911
5912 MODULE_PARM_DESC(tvyposoffset,
5913         "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5914           "Default: 0\n");
5915
5916 MODULE_PARM_DESC(filter,
5917         "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5918           "(Possible values 0-7, default: [no filter])\n");
5919
5920 MODULE_PARM_DESC(nocrt2rate,
5921         "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5922           "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5923
5924 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5925 MODULE_PARM_DESC(inverse,
5926         "\nSetting this to anything but 0 should invert the display colors, but this\n"
5927           "does not seem to work. (default: 0)\n");
5928 #endif
5929
5930 #if !defined(__i386__) && !defined(__x86_64__)
5931 #ifdef CONFIG_FB_SIS_300
5932 MODULE_PARM_DESC(resetcard,
5933         "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5934           "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5935           "Default: 0\n");
5936
5937 MODULE_PARM_DESC(videoram,
5938         "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5939           "some non-x86 architectures where the memory auto detection fails. Only\n"
5940           "relevant if resetcard is set, too. Default: [auto-detect]\n");
5941 #endif
5942 #endif
5943
5944 static int __devinit sisfb_init_module(void)
5945 {
5946         sisfb_setdefaultparms();
5947
5948         if(rate) sisfb_parm_rate = rate;
5949
5950         if((scalelcd == 0) || (scalelcd == 1)) {
5951            sisfb_scalelcd = scalelcd ^ 1;
5952         }
5953
5954         /* Need to check crt2 type first for fstn/dstn */
5955
5956         if(forcecrt2type)
5957                 sisfb_search_crt2type(forcecrt2type);
5958
5959         if(tvstandard)
5960                 sisfb_search_tvstd(tvstandard);
5961
5962         if(mode)
5963                 sisfb_search_mode(mode, FALSE);
5964         else if(vesa != -1)
5965                 sisfb_search_vesamode(vesa, FALSE);
5966
5967         sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5968
5969         sisfb_forcecrt1 = forcecrt1;
5970         if(forcecrt1 == 1)      sisfb_crt1off = 0;
5971         else if(forcecrt1 == 0) sisfb_crt1off = 1;
5972
5973         if(noaccel == 1)      sisfb_accel = 0;
5974         else if(noaccel == 0) sisfb_accel = 1;
5975
5976         if(noypan == 1)       sisfb_ypan = 0;
5977         else if(noypan == 0)  sisfb_ypan = 1;
5978
5979         if(nomax == 1)        sisfb_max = 0;
5980         else if(nomax == 0)   sisfb_max = 1;
5981         
5982 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5983         if(inverse)           sisfb_inverse = 1;
5984 #endif
5985
5986         if(mem)               sisfb_parm_mem = mem;
5987
5988         if(userom != -1)      sisfb_userom = userom;
5989         if(useoem != -1)      sisfb_useoem = useoem;
5990
5991         if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
5992         if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
5993
5994         sisfb_nocrt2rate = nocrt2rate;
5995
5996         if(specialtiming)
5997                 sisfb_search_specialtiming(specialtiming);
5998
5999         if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
6000
6001         if(filter != -1) sisfb_filter = filter;
6002
6003         sisfb_tvxposoffset = tvxposoffset;
6004         sisfb_tvyposoffset = tvyposoffset;
6005
6006 #if !defined(__i386__) && !defined(__x86_64__)
6007         sisfb_resetcard = (resetcard) ? 1 : 0;
6008         if(videoram)    sisfb_videoram = videoram;
6009 #endif
6010
6011         return(sisfb_init());
6012 }
6013
6014 static void __exit sisfb_remove_module(void)
6015 {
6016         pci_unregister_driver(&sisfb_driver);
6017         printk(KERN_DEBUG "sisfb: Module unloaded\n");
6018 }
6019
6020 module_init(sisfb_init_module);
6021 module_exit(sisfb_remove_module);
6022
6023 #endif     /*  /MODULE  */
6024
6025 EXPORT_SYMBOL(sis_malloc);
6026 EXPORT_SYMBOL(sis_free);
6027
6028