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