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