vserver 1.9.3
[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         sisfb_get_fix(&info->fix, info->currcon, info);
1817
1818         return 0;
1819 }
1820
1821 static int
1822 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1823 {
1824         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1825         unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1826         unsigned int drate = 0, hrate = 0, maxyres;
1827         int found_mode = 0;
1828         int refresh_rate, search_idx;
1829         BOOLEAN recalc_clock = FALSE;
1830         u32 pixclock;
1831
1832         htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1833
1834         vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1835
1836         pixclock = var->pixclock;
1837
1838         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1839                 vtotal += var->yres;
1840                 vtotal <<= 1;
1841         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1842                 vtotal += var->yres;
1843                 vtotal <<= 2;
1844         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1845                 vtotal += var->yres;
1846                 vtotal <<= 1;
1847         } else  vtotal += var->yres;
1848
1849         if(!(htotal) || !(vtotal)) {
1850                 SISFAIL("sisfb: no valid timing data");
1851         }
1852
1853         search_idx = 0;
1854         while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1855                (sisbios_mode[search_idx].xres <= var->xres) ) {
1856                 if( (sisbios_mode[search_idx].xres == var->xres) &&
1857                     (sisbios_mode[search_idx].yres == var->yres) &&
1858                     (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1859                         if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
1860                            found_mode = 1;
1861                            break;
1862                         }
1863                 }
1864                 search_idx++;
1865         }
1866
1867         if(!found_mode) {
1868                 search_idx = 0;
1869                 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1870                    if( (var->xres <= sisbios_mode[search_idx].xres) &&
1871                        (var->yres <= sisbios_mode[search_idx].yres) &&
1872                        (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1873                           if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
1874                              found_mode = 1;
1875                              break;
1876                           }
1877                    }
1878                    search_idx++;
1879                 }
1880                 if(found_mode) {
1881                         printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1882                                 var->xres, var->yres, var->bits_per_pixel,
1883                                 sisbios_mode[search_idx].xres,
1884                                 sisbios_mode[search_idx].yres,
1885                                 var->bits_per_pixel);
1886                         var->xres = sisbios_mode[search_idx].xres;
1887                         var->yres = sisbios_mode[search_idx].yres;
1888
1889
1890                 } else {
1891                         printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",
1892                                 var->xres, var->yres, var->bits_per_pixel);
1893                         return -EINVAL;
1894                 }
1895         }
1896
1897         if( ((ivideo->vbflags & VB_LVDS) ||                     /* Slave modes on LVDS and 301B-DH */
1898              ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1899             (var->bits_per_pixel == 8) ) {
1900                 refresh_rate = 60;
1901                 recalc_clock = TRUE;
1902         } else if( (ivideo->current_htotal == htotal) &&        /* x=x & y=y & c=c -> assume depth change */
1903                    (ivideo->current_vtotal == vtotal) &&
1904                    (ivideo->current_pixclock == pixclock) ) {
1905                 drate = 1000000000 / pixclock;
1906                 hrate = (drate * 1000) / htotal;
1907                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1908         } else if( ( (ivideo->current_htotal != htotal) ||      /* x!=x | y!=y & c=c -> invalid pixclock */
1909                      (ivideo->current_vtotal != vtotal) ) &&
1910                    (ivideo->current_pixclock == var->pixclock) ) {
1911                 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1912                         refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1913                 } else if(ivideo->sisfb_parm_rate != -1) {
1914                         /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1915                         refresh_rate = ivideo->sisfb_parm_rate;
1916                 } else {
1917                         refresh_rate = 60;
1918                 }
1919                 recalc_clock = TRUE;
1920         } else if((pixclock) && (htotal) && (vtotal)) {
1921                 drate = 1000000000 / pixclock;
1922                 hrate = (drate * 1000) / htotal;
1923                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1924         } else if(ivideo->current_refresh_rate) {
1925                 refresh_rate = ivideo->current_refresh_rate;
1926                 recalc_clock = TRUE;
1927         } else {
1928                 refresh_rate = 60;
1929                 recalc_clock = TRUE;
1930         }
1931
1932         myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1933
1934         /* Eventually recalculate timing and clock */
1935         if(recalc_clock) {
1936            if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1937            var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1938                                                 &ivideo->sishw_ext,
1939                                                 sisbios_mode[search_idx].mode_no[ivideo->mni],
1940                                                 myrateindex));
1941            sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
1942                                     sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var);
1943            if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1944               var->pixclock <<= 1;
1945            }
1946         }
1947
1948         if(ivideo->sisfb_thismonitor.datavalid) {
1949            if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1950                                  myrateindex, refresh_rate)) {
1951               printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1952            }
1953         }
1954
1955         /* Adapt RGB settings */
1956         sisfb_bpp_to_var(ivideo, var);
1957         
1958         /* Sanity check for offsets */
1959         if(var->xoffset < 0) var->xoffset = 0;
1960         if(var->yoffset < 0) var->yoffset = 0;
1961
1962         if(var->xres > var->xres_virtual) {
1963            var->xres_virtual = var->xres;
1964         }
1965
1966         if(ivideo->sisfb_ypan) {
1967            maxyres = sisfb_calc_maxyres(ivideo, var);
1968            if(ivideo->sisfb_max) {
1969               var->yres_virtual = maxyres;
1970            } else {
1971               if(var->yres_virtual > maxyres) {
1972                  var->yres_virtual = maxyres;
1973               }
1974            }
1975            if(var->yres_virtual <= var->yres) {
1976               var->yres_virtual = var->yres;
1977            }
1978         } else {
1979            if(var->yres != var->yres_virtual) {
1980               var->yres_virtual = var->yres;
1981            }
1982            var->xoffset = 0;
1983            var->yoffset = 0;
1984         }
1985         
1986         /* Truncate offsets to maximum if too high */
1987         if(var->xoffset > var->xres_virtual - var->xres) {
1988            var->xoffset = var->xres_virtual - var->xres - 1;
1989         }
1990
1991         if(var->yoffset > var->yres_virtual - var->yres) {
1992            var->yoffset = var->yres_virtual - var->yres - 1;
1993         }
1994         
1995         /* Set everything else to 0 */
1996         var->red.msb_right = 
1997         var->green.msb_right =
1998         var->blue.msb_right =
1999         var->transp.offset =
2000         var->transp.length =
2001         var->transp.msb_right = 0;
2002
2003         return 0;
2004 }
2005
2006 static int
2007 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
2008 {
2009         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2010         int err;
2011
2012         if(var->xoffset > (var->xres_virtual - var->xres)) {
2013                 return -EINVAL;
2014         }
2015         if(var->yoffset > (var->yres_virtual - var->yres)) {
2016                 return -EINVAL;
2017         }
2018
2019         if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
2020
2021         if(var->xoffset + info->var.xres > info->var.xres_virtual ||
2022            var->yoffset + info->var.yres > info->var.yres_virtual) {
2023                 return -EINVAL;
2024         }
2025
2026         if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
2027
2028         info->var.xoffset = var->xoffset;
2029         info->var.yoffset = var->yoffset;
2030
2031         return 0;
2032 }
2033
2034 static int
2035 sisfb_blank(int blank, struct fb_info *info)
2036 {
2037         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2038
2039         return(sisfb_myblank(ivideo, blank));
2040 }
2041
2042 #endif
2043
2044 /* ----------- FBDev related routines for all series ---------- */
2045
2046 static int
2047 sisfb_ioctl(struct inode *inode, struct file *file,
2048             unsigned int cmd, unsigned long arg,
2049 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2050             int con,
2051 #endif
2052             struct fb_info *info)
2053 {
2054         struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
2055         struct sis_memreq       sismemreq;
2056         struct fb_vblank        sisvbblank;
2057         sisfb_info              x;
2058         u32                     gpu32 = 0;
2059         static int              count = 0;
2060         u32 __user              *argp = (u32 __user *) arg;
2061
2062         switch (cmd) {
2063            case FBIO_ALLOC:
2064                 if(!capable(CAP_SYS_RAWIO)) {
2065                         return -EPERM;
2066                 }
2067                 if(copy_from_user(&sismemreq, argp, sizeof(sismemreq))) {
2068                         return -EFAULT;
2069                 }
2070                 sis_malloc(&sismemreq);
2071                 if(copy_to_user(argp, &sismemreq, sizeof(sismemreq))) {
2072                         sis_free((u32)sismemreq.offset);
2073                         return -EFAULT;
2074                 }
2075                 break;
2076
2077            case FBIO_FREE:
2078                 if(!capable(CAP_SYS_RAWIO)) {
2079                         return -EPERM;
2080                 }
2081                 if(get_user(gpu32, argp)) {
2082                         return -EFAULT;
2083                 }
2084                 sis_free(gpu32);
2085                 break;
2086
2087            case FBIOGET_VBLANK:
2088                 sisvbblank.count = 0;
2089                 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
2090                 if(copy_to_user(argp, &sisvbblank, sizeof(sisvbblank))) {
2091                         return -EFAULT;
2092                 }
2093                 break;
2094
2095            case SISFB_GET_INFO_SIZE:
2096                 return put_user(sizeof(sisfb_info), argp);
2097
2098            case SISFB_GET_INFO_OLD:
2099                 if(++count < 50) {
2100                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2101                 }
2102            case SISFB_GET_INFO:  /* For communication with X driver */
2103                 x.sisfb_id         = SISFB_ID;
2104                 x.sisfb_version    = VER_MAJOR;
2105                 x.sisfb_revision   = VER_MINOR;
2106                 x.sisfb_patchlevel = VER_LEVEL;
2107                 x.chip_id = ivideo->chip_id;
2108                 x.memory = ivideo->video_size / 1024;
2109                 x.heapstart = ivideo->heapstart / 1024;
2110                 if(ivideo->modechanged) {
2111                    x.fbvidmode = ivideo->mode_no;
2112                 } else {
2113                    x.fbvidmode = ivideo->modeprechange;
2114                 }
2115                 x.sisfb_caps = ivideo->caps;
2116                 x.sisfb_tqlen = 512; /* yet fixed */
2117                 x.sisfb_pcibus = ivideo->pcibus;
2118                 x.sisfb_pcislot = ivideo->pcislot;
2119                 x.sisfb_pcifunc = ivideo->pcifunc;
2120                 x.sisfb_lcdpdc = ivideo->detectedpdc;
2121                 x.sisfb_lcdpdca = ivideo->detectedpdca;
2122                 x.sisfb_lcda = ivideo->detectedlcda;
2123                 x.sisfb_vbflags = ivideo->vbflags;
2124                 x.sisfb_currentvbflags = ivideo->currentvbflags;
2125                 x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
2126                 x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
2127                 x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
2128                 x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
2129                 x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
2130                 x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
2131                 x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
2132                 x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
2133                 x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
2134                 x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
2135
2136                 if(copy_to_user(argp, &x, sizeof(x))) {
2137                         return -EFAULT;
2138                 }
2139                 break;
2140
2141            case SISFB_GET_VBRSTATUS_OLD:
2142                 if(++count < 50) {
2143                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2144                 }
2145            case SISFB_GET_VBRSTATUS:
2146                 if(sisfb_CheckVBRetrace(ivideo)) {
2147                         return put_user((u32)1, argp);
2148                 } else {
2149                         return put_user((u32)0, argp);
2150                 }
2151
2152            case SISFB_GET_AUTOMAXIMIZE_OLD:
2153                 if(++count < 50) {
2154                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2155                 }
2156            case SISFB_GET_AUTOMAXIMIZE:
2157                 if(ivideo->sisfb_max) return put_user((u32)1, argp);
2158                 else                  return put_user((u32)0, argp);
2159
2160            case SISFB_SET_AUTOMAXIMIZE_OLD:
2161                 if(++count < 50) {
2162                    printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
2163                 }
2164            case SISFB_SET_AUTOMAXIMIZE:
2165                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2166                         return -EFAULT;
2167                 }
2168                 ivideo->sisfb_max = (gpu32) ? 1 : 0;
2169                 break;
2170
2171            case SISFB_SET_TVPOSOFFSET:
2172                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2173                         return -EFAULT;
2174                 }
2175                 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
2176                 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
2177                 break;
2178
2179            case SISFB_GET_TVPOSOFFSET:
2180                 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), argp);
2181
2182            case SISFB_SET_LOCK:
2183                 if(copy_from_user(&gpu32, argp, sizeof(gpu32))) {
2184                         return -EFAULT;
2185                 }
2186                 ivideo->sisfblocked = (gpu32) ? 1 : 0;
2187                 break;
2188
2189            default:
2190                 return -EINVAL;
2191         }
2192         return 0;
2193 }
2194
2195 static int
2196 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
2197 {
2198         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
2199
2200         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2201
2202         strcpy(fix->id, ivideo->myid);
2203
2204         fix->smem_start  = ivideo->video_base;
2205         fix->smem_len    = ivideo->sisfb_mem;
2206         fix->type        = FB_TYPE_PACKED_PIXELS;
2207         fix->type_aux    = 0;
2208         fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2209         fix->xpanstep    = 1;
2210         fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
2211         fix->ywrapstep   = 0;
2212         fix->line_length = ivideo->video_linelength;
2213         fix->mmio_start  = ivideo->mmio_base;
2214         fix->mmio_len    = ivideo->mmio_size;
2215         if(ivideo->sisvga_engine == SIS_300_VGA) {
2216            fix->accel    = FB_ACCEL_SIS_GLAMOUR;
2217         } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
2218            fix->accel    = FB_ACCEL_SIS_XABRE;
2219         } else {
2220            fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
2221         }
2222
2223         return 0;
2224 }
2225
2226 /* ----------------  fb_ops structures ----------------- */
2227
2228 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
2229 static struct fb_ops sisfb_ops = {
2230         .owner          = THIS_MODULE,
2231         .fb_get_fix     = sisfb_get_fix,
2232         .fb_get_var     = sisfb_get_var,
2233         .fb_set_var     = sisfb_set_var,
2234         .fb_get_cmap    = sisfb_get_cmap,
2235         .fb_set_cmap    = sisfb_set_cmap,
2236         .fb_pan_display = sisfb_pan_display,
2237         .fb_ioctl       = sisfb_ioctl
2238 };
2239 #endif
2240
2241 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
2242 static struct fb_ops sisfb_ops = {
2243         .owner          = THIS_MODULE,
2244         .fb_open        = sisfb_open,
2245         .fb_release     = sisfb_release,
2246         .fb_check_var   = sisfb_check_var,
2247         .fb_set_par     = sisfb_set_par,
2248         .fb_setcolreg   = sisfb_setcolreg,
2249         .fb_pan_display = sisfb_pan_display,
2250         .fb_blank       = sisfb_blank,
2251         .fb_fillrect    = fbcon_sis_fillrect,
2252         .fb_copyarea    = fbcon_sis_copyarea,
2253         .fb_imageblit   = cfb_imageblit,
2254         .fb_cursor      = soft_cursor,
2255         .fb_sync        = fbcon_sis_sync,
2256         .fb_ioctl       = sisfb_ioctl
2257 };
2258 #endif
2259
2260 /* ---------------- Chip generation dependent routines ---------------- */
2261
2262 static struct pci_dev * sisfb_get_northbridge(int basechipid)
2263 {
2264         struct pci_dev *pdev = NULL;
2265         int nbridgenum, nbridgeidx, i;
2266         const unsigned short nbridgeids[] = {
2267                 PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
2268                 PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
2269                 PCI_DEVICE_ID_SI_730,
2270                 PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
2271                 PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
2272                 PCI_DEVICE_ID_SI_651,
2273                 PCI_DEVICE_ID_SI_740,
2274                 PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760 VGA */
2275                 PCI_DEVICE_ID_SI_741,
2276                 PCI_DEVICE_ID_SI_660,
2277                 PCI_DEVICE_ID_SI_760
2278         };
2279
2280         switch(basechipid) {
2281 #ifdef CONFIG_FB_SIS_300
2282         case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
2283         case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
2284 #endif
2285 #ifdef CONFIG_FB_SIS_315
2286         case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
2287         case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
2288         case SIS_660:   nbridgeidx = 7; nbridgenum = 4; break;
2289 #endif
2290         default:        return NULL;
2291         }
2292         for(i = 0; i < nbridgenum; i++) {
2293                 if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
2294         }
2295         return pdev;
2296 }
2297
2298 static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
2299 {
2300 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2301         u8 reg;
2302 #endif
2303
2304         ivideo->video_size = 0;
2305
2306         switch(ivideo->chip) {
2307 #ifdef CONFIG_FB_SIS_300
2308         case SIS_300:
2309                 inSISIDXREG(SISSR, 0x14, reg);
2310                 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2311                 break;
2312         case SIS_540:
2313         case SIS_630:
2314         case SIS_730:
2315                 if(!ivideo->nbridge) return -1;
2316                 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2317                 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2318                 break;
2319 #endif
2320 #ifdef CONFIG_FB_SIS_315
2321         case SIS_315H:
2322         case SIS_315PRO:
2323         case SIS_315:
2324                 inSISIDXREG(SISSR, 0x14, reg);
2325                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2326                 switch((reg >> 2) & 0x03) {
2327                 case 0x01:
2328                 case 0x03:
2329                    ivideo->video_size <<= 1;
2330                    break;
2331                 case 0x02:
2332                    ivideo->video_size += (ivideo->video_size/2);
2333                 }
2334                 break;
2335         case SIS_330:
2336                 inSISIDXREG(SISSR, 0x14, reg);
2337                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2338                 if(reg & 0x0c) ivideo->video_size <<= 1;
2339                 break;
2340         case SIS_550:
2341         case SIS_650:
2342         case SIS_740:
2343                 inSISIDXREG(SISSR, 0x14, reg);
2344                 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2345                 break;
2346         case SIS_661:
2347         case SIS_741:
2348                 inSISIDXREG(SISCR, 0x79, reg);
2349                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2350                 break;
2351         case SIS_660:
2352         case SIS_760:
2353                 inSISIDXREG(SISCR, 0x79, reg);
2354                 reg = (reg & 0xf0) >> 4;
2355                 if(reg) ivideo->video_size = (1 << reg) << 20;
2356                 inSISIDXREG(SISCR, 0x78, reg);
2357                 reg &= 0x30;
2358                 if(reg) {
2359                    if(reg == 0x10) ivideo->video_size += (32 << 20);
2360                    else            ivideo->video_size += (64 << 20);
2361                 }
2362                 break;
2363 #endif
2364         default:
2365                 return -1;
2366         }
2367         return 0;
2368 }
2369
2370 /* -------------- video bridge device detection --------------- */
2371
2372 static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2373 {
2374         u8 cr32, temp;
2375
2376 #ifdef CONFIG_FB_SIS_300
2377         if(ivideo->sisvga_engine == SIS_300_VGA) {
2378                 inSISIDXREG(SISSR, 0x17, temp);
2379                 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2380                         /* PAL/NTSC is stored on SR16 on such machines */
2381                         if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2382                                 inSISIDXREG(SISSR, 0x16, temp);
2383                                 if(temp & 0x20)
2384                                         ivideo->vbflags |= TV_PAL;
2385                                 else
2386                                         ivideo->vbflags |= TV_NTSC;
2387                         }
2388                 }
2389         }
2390 #endif
2391
2392         inSISIDXREG(SISCR, 0x32, cr32);
2393
2394         if(cr32 & SIS_CRT1) {
2395                 ivideo->sisfb_crt1off = 0;
2396         } else {
2397                 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2398         }
2399
2400         ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2401
2402         if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2403         if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2404         if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2405
2406         /* Check given parms for hardware compatibility.
2407          * (Cannot do this in the search_xx routines since we don't
2408          * know what hardware we are running on then)
2409          */
2410
2411         if(ivideo->chip != SIS_550) {
2412            ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2413         }
2414
2415         if(ivideo->sisfb_tvplug != -1) {
2416            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2417                (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
2418               if(ivideo->sisfb_tvplug & TV_YPBPR) {
2419                  ivideo->sisfb_tvplug = -1;
2420                  printk(KERN_ERR "sisfb: YPbPr not supported\n");
2421               }
2422            }
2423         }
2424         if(ivideo->sisfb_tvplug != -1) {
2425            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2426                (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
2427               if(ivideo->sisfb_tvplug & TV_HIVISION) {
2428                  ivideo->sisfb_tvplug = -1;
2429                  printk(KERN_ERR "sisfb: HiVision not supported\n");
2430               }
2431            }
2432         }
2433         if(ivideo->sisfb_tvstd != -1) {
2434            if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
2435                (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
2436               if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2437                  ivideo->sisfb_tvstd = -1;
2438                  printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2439               }
2440            }
2441         }
2442
2443         /* Detect/set TV plug & type */
2444         if(ivideo->sisfb_tvplug != -1) {
2445                 ivideo->vbflags |= ivideo->sisfb_tvplug;
2446         } else {
2447                 if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2448                 else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2449                 else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2450                 else {
2451                         if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2452                         if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2453                 }
2454         }
2455
2456         if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2457             if(ivideo->sisfb_tvstd != -1) {
2458                ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2459                ivideo->vbflags |= ivideo->sisfb_tvstd;
2460             }
2461             if(ivideo->vbflags & TV_SCART) {
2462                ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2463                ivideo->vbflags |= TV_PAL;
2464             }
2465             if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2466                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2467                         inSISIDXREG(SISSR, 0x38, temp);
2468                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2469                         else            ivideo->vbflags |= TV_NTSC;
2470                 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2471                         inSISIDXREG(SISSR, 0x38, temp);
2472                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2473                         else            ivideo->vbflags |= TV_NTSC;
2474                 } else {
2475                         inSISIDXREG(SISCR, 0x79, temp);
2476                         if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2477                         else            ivideo->vbflags |= TV_NTSC;
2478                 }
2479             }
2480         }
2481
2482         /* Copy forceCRT1 option to CRT1off if option is given */
2483         if(ivideo->sisfb_forcecrt1 != -1) {
2484            ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2485         }
2486 }
2487
2488 static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
2489 {
2490         char stdstr[]    = "sisfb: Detected";
2491         char bridgestr[] = "video bridge";
2492         u8 vb_chipid;
2493         u8 reg;
2494
2495         inSISIDXREG(SISPART4, 0x00, vb_chipid);
2496         switch(vb_chipid) {
2497         case 0x01:
2498                 inSISIDXREG(SISPART4, 0x01, reg);
2499                 if(reg < 0xb0) {
2500                         ivideo->vbflags |= VB_301;
2501                         printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2502                 } else if(reg < 0xc0) {
2503                         ivideo->vbflags |= VB_301B;
2504                         inSISIDXREG(SISPART4,0x23,reg);
2505                         if(!(reg & 0x02)) {
2506                            ivideo->vbflags |= VB_30xBDH;
2507                            printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2508                         } else {
2509                            printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2510                         }
2511                 } else if(reg < 0xd0) {
2512                         ivideo->vbflags |= VB_301C;
2513                         printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2514                 } else if(reg < 0xe0) {
2515                         ivideo->vbflags |= VB_301LV;
2516                         printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2517                 } else if(reg <= 0xe1) {
2518                         inSISIDXREG(SISPART4,0x39,reg);
2519                         if(reg == 0xff) {
2520                            ivideo->vbflags |= VB_302LV;
2521                            printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2522                         } else {
2523                            ivideo->vbflags |= VB_301C;
2524                            printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2525 #if 0
2526                            ivideo->vbflags |= VB_302ELV;
2527                            printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2528 #endif
2529                         }
2530                 }
2531                 break;
2532         case 0x02:
2533                 ivideo->vbflags |= VB_302B;
2534                 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2535                 break;
2536         }
2537
2538         if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2539                 inSISIDXREG(SISCR, 0x37, reg);
2540                 reg &= SIS_EXTERNAL_CHIP_MASK;
2541                 reg >>= 1;
2542                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2543 #ifdef CONFIG_FB_SIS_300
2544                         switch(reg) {
2545                            case SIS_EXTERNAL_CHIP_LVDS:
2546                                 ivideo->vbflags |= VB_LVDS;
2547                                 break;
2548                            case SIS_EXTERNAL_CHIP_TRUMPION:
2549                                 ivideo->vbflags |= VB_TRUMPION;
2550                                 break;
2551                            case SIS_EXTERNAL_CHIP_CHRONTEL:
2552                                 ivideo->vbflags |= VB_CHRONTEL;
2553                                 break;
2554                            case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2555                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2556                                 break;
2557                         }
2558                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
2559 #endif
2560                 } else if(ivideo->chip < SIS_661) {
2561 #ifdef CONFIG_FB_SIS_315
2562                         switch (reg) {
2563                            case SIS310_EXTERNAL_CHIP_LVDS:
2564                                 ivideo->vbflags |= VB_LVDS;
2565                                 break;
2566                            case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2567                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2568                                 break;
2569                         }
2570                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2571 #endif
2572                 } else if(ivideo->chip >= SIS_661) {
2573 #ifdef CONFIG_FB_SIS_315
2574                         inSISIDXREG(SISCR, 0x38, reg);
2575                         reg >>= 5;
2576                         switch(reg) {
2577                            case 0x02:
2578                                 ivideo->vbflags |= VB_LVDS;
2579                                 break;
2580                            case 0x03:
2581                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
2582                                 break;
2583                            case 0x04:
2584                                 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
2585                                 break;
2586                         }
2587                         if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
2588 #endif
2589                 }
2590                 if(ivideo->vbflags & VB_LVDS) {
2591                    printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2592                 }
2593                 if(ivideo->vbflags & VB_TRUMPION) {
2594                    printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2595                 }
2596                 if(ivideo->vbflags & VB_CHRONTEL) {
2597                    printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2598                 }
2599                 if(ivideo->vbflags & VB_CONEXANT) {
2600                    printk(KERN_INFO "%s Conexant external device\n", stdstr);
2601                 }
2602         }
2603
2604         if(ivideo->vbflags & VB_SISBRIDGE) {
2605                 SiS_Sense30x(ivideo);
2606         } else if(ivideo->vbflags & VB_CHRONTEL) {
2607                 SiS_SenseCh(ivideo);
2608         }
2609 }
2610
2611 /* ------------------ Sensing routines ------------------ */
2612
2613 static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
2614 {
2615     unsigned short old;
2616     int count = 48;
2617
2618     old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2619     do {
2620         if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2621     } while(count--);
2622     return (count == -1) ? FALSE : TRUE;
2623 }
2624
2625 static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
2626 {
2627     BOOLEAN mustwait = FALSE;
2628     u8  SR1F, CR17;
2629 #ifdef CONFIG_FB_SIS_315
2630     u8  CR63=0;
2631 #endif
2632     u16 temp = 0xffff;
2633     int i;
2634
2635     inSISIDXREG(SISSR,0x1F,SR1F);
2636     orSISIDXREG(SISSR,0x1F,0x04);
2637     andSISIDXREG(SISSR,0x1F,0x3F);
2638     if(SR1F & 0xc0) mustwait = TRUE;
2639
2640 #ifdef CONFIG_FB_SIS_315
2641     if(ivideo->sisvga_engine == SIS_315_VGA) {
2642        inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,CR63);
2643        CR63 &= 0x40;
2644        andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2645     }
2646 #endif
2647
2648     inSISIDXREG(SISCR,0x17,CR17);
2649     CR17 &= 0x80;
2650     if(!CR17) {
2651        orSISIDXREG(SISCR,0x17,0x80);
2652        mustwait = TRUE;
2653        outSISIDXREG(SISSR, 0x00, 0x01);
2654        outSISIDXREG(SISSR, 0x00, 0x03);
2655     }
2656
2657     if(mustwait) {
2658        for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2659     }
2660
2661 #ifdef CONFIG_FB_SIS_315
2662     if(ivideo->chip >= SIS_330) {
2663        andSISIDXREG(SISCR,0x32,~0x20);
2664        if(ivideo->chip >= SIS_340) {
2665           outSISIDXREG(SISCR, 0x57, 0x4a);
2666        } else {
2667           outSISIDXREG(SISCR, 0x57, 0x5f);
2668        }
2669        orSISIDXREG(SISCR, 0x53, 0x02);
2670        while((inSISREG(SISINPSTAT)) & 0x01)    break;
2671        while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2672        if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2673        andSISIDXREG(SISCR, 0x53, 0xfd);
2674        andSISIDXREG(SISCR, 0x57, 0x00);
2675     }
2676 #endif
2677
2678     if(temp == 0xffff) {
2679        i = 3;
2680        do {
2681           temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
2682        } while(((temp == 0) || (temp == 0xffff)) && i--);
2683
2684        if((temp == 0) || (temp == 0xffff)) {
2685           if(sisfb_test_DDC1(ivideo)) temp = 1;
2686        }
2687     }
2688
2689     if((temp) && (temp != 0xffff)) {
2690        orSISIDXREG(SISCR,0x32,0x20);
2691     }
2692
2693 #ifdef CONFIG_FB_SIS_315
2694     if(ivideo->sisvga_engine == SIS_315_VGA) {
2695        setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,CR63);
2696     }
2697 #endif
2698
2699     setSISIDXREG(SISCR,0x17,0x7F,CR17);
2700
2701     outSISIDXREG(SISSR,0x1F,SR1F);
2702 }
2703
2704 /* Determine and detect attached devices on SiS30x */
2705 static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2706 {
2707     int temp, mytest, result, i, j;
2708
2709     for(j = 0; j < 10; j++) {
2710        result = 0;
2711        for(i = 0; i < 3; i++) {
2712           mytest = test;
2713           outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2714           temp = (type >> 8) | (mytest & 0x00ff);
2715           setSISIDXREG(SISPART4,0x10,0xe0,temp);
2716           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2717           mytest >>= 8;
2718           mytest &= 0x7f;
2719           inSISIDXREG(SISPART4,0x03,temp);
2720           temp ^= 0x0e;
2721           temp &= mytest;
2722           if(temp == mytest) result++;
2723 #if 1
2724           outSISIDXREG(SISPART4,0x11,0x00);
2725           andSISIDXREG(SISPART4,0x10,0xe0);
2726           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2727 #endif
2728        }
2729        if((result == 0) || (result >= 2)) break;
2730     }
2731     return(result);
2732 }
2733
2734 static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
2735 {
2736     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2737     u16 svhs=0, svhs_c=0;
2738     u16 cvbs=0, cvbs_c=0;
2739     u16 vga2=0, vga2_c=0;
2740     int myflag, result;
2741     char stdstr[] = "sisfb: Detected";
2742     char tvstr[]  = "TV connected to";
2743
2744     if(ivideo->vbflags & VB_301) {
2745        svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2746        inSISIDXREG(SISPART4,0x01,myflag);
2747        if(myflag & 0x04) {
2748           svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2749        }
2750     } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
2751        svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2752     } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
2753        svhs = 0x0200; cvbs = 0x0100;
2754     } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
2755        svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2756     } else return;
2757
2758     vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2759     if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
2760        svhs_c = 0x0408; cvbs_c = 0x0808;
2761     }
2762     biosflag = 2;
2763
2764     if(ivideo->chip == SIS_300) {
2765        inSISIDXREG(SISSR,0x3b,myflag);
2766        if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2767     }
2768
2769     inSISIDXREG(SISSR,0x1e,backupSR_1e);
2770     orSISIDXREG(SISSR,0x1e,0x20);
2771
2772     inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2773     if(ivideo->vbflags & VB_301C) {
2774        setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2775     } else {
2776        orSISIDXREG(SISPART4,0x0d,0x04);
2777     }
2778     SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2779
2780     inSISIDXREG(SISPART2,0x00,backupP2_00);
2781     outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2782
2783     inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2784     if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
2785        outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2786     }
2787
2788     if(!(ivideo->vbflags & VB_301C)) {
2789        SISDoSense(ivideo, 0, 0);
2790     }
2791
2792     andSISIDXREG(SISCR, 0x32, ~0x14);
2793
2794     if(vga2_c || vga2) {
2795        if(SISDoSense(ivideo, vga2, vga2_c)) {
2796           if(biosflag & 0x01) {
2797              printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2798              orSISIDXREG(SISCR, 0x32, 0x04);
2799           } else {
2800              printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2801              orSISIDXREG(SISCR, 0x32, 0x10);
2802           }
2803        }
2804     }
2805
2806     andSISIDXREG(SISCR, 0x32, 0x3f);
2807
2808     if(ivideo->vbflags & VB_301C) {
2809        orSISIDXREG(SISPART4,0x0d,0x04);
2810     }
2811
2812     if((ivideo->sisvga_engine == SIS_315_VGA) &&
2813        (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
2814        outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2815        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2816        if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2817           if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2818              printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2819              orSISIDXREG(SISCR,0x32,0x80);
2820           }
2821        }
2822        outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2823     }
2824
2825     andSISIDXREG(SISCR, 0x32, ~0x03);
2826
2827     if(!(ivideo->vbflags & TV_YPBPR)) {
2828        if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2829           printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2830           orSISIDXREG(SISCR, 0x32, 0x02);
2831        }
2832        if((biosflag & 0x02) || (!result)) {
2833           if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2834              printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2835              orSISIDXREG(SISCR, 0x32, 0x01);
2836           }
2837        }
2838     }
2839
2840     SISDoSense(ivideo, 0, 0);
2841
2842     outSISIDXREG(SISPART2,0x00,backupP2_00);
2843     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2844     outSISIDXREG(SISSR,0x1e,backupSR_1e);
2845
2846     if(ivideo->vbflags & VB_301C) {
2847        inSISIDXREG(SISPART2,0x00,biosflag);
2848        if(biosflag & 0x20) {
2849           for(myflag = 2; myflag > 0; myflag--) {
2850              biosflag ^= 0x20;
2851              outSISIDXREG(SISPART2,0x00,biosflag);
2852           }
2853        }
2854     }
2855
2856     outSISIDXREG(SISPART2,0x00,backupP2_00);
2857 }
2858
2859 /* Determine and detect attached TV's on Chrontel */
2860 static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
2861 {
2862 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2863     u8 temp1, temp2;
2864     char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2865 #endif
2866 #ifdef CONFIG_FB_SIS_300
2867     unsigned char test[3];
2868     int i;
2869 #endif
2870
2871     if(ivideo->chip < SIS_315H) {
2872
2873 #ifdef CONFIG_FB_SIS_300
2874        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2875        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2876        SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2877        temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2878        /* See Chrontel TB31 for explanation */
2879        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2880        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2881           SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
2882           SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2883        }
2884        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2885        if(temp2 != temp1) temp1 = temp2;
2886
2887        if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2888            /* Read power status */
2889            temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2890            if((temp1 & 0x03) != 0x03) {
2891                 /* Power all outputs */
2892                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
2893                 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2894            }
2895            /* Sense connected TV devices */
2896            for(i = 0; i < 3; i++) {
2897                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
2898                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2899                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
2900                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2901                temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2902                if(!(temp1 & 0x08))       test[i] = 0x02;
2903                else if(!(temp1 & 0x02))  test[i] = 0x01;
2904                else                      test[i] = 0;
2905                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2906            }
2907
2908            if(test[0] == test[1])      temp1 = test[0];
2909            else if(test[0] == test[2]) temp1 = test[0];
2910            else if(test[1] == test[2]) temp1 = test[1];
2911            else {
2912                 printk(KERN_INFO
2913                         "sisfb: TV detection unreliable - test results varied\n");
2914                 temp1 = test[2];
2915            }
2916            if(temp1 == 0x02) {
2917                 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2918                 ivideo->vbflags |= TV_SVIDEO;
2919                 orSISIDXREG(SISCR, 0x32, 0x02);
2920                 andSISIDXREG(SISCR, 0x32, ~0x05);
2921            } else if (temp1 == 0x01) {
2922                 printk(KERN_INFO "%s CVBS output\n", stdstr);
2923                 ivideo->vbflags |= TV_AVIDEO;
2924                 orSISIDXREG(SISCR, 0x32, 0x01);
2925                 andSISIDXREG(SISCR, 0x32, ~0x06);
2926            } else {
2927                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2928                 andSISIDXREG(SISCR, 0x32, ~0x07);
2929            }
2930        } else if(temp1 == 0) {
2931           SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
2932           andSISIDXREG(SISCR, 0x32, ~0x07);
2933        }
2934        /* Set general purpose IO for Chrontel communication */
2935        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2936 #endif
2937
2938     } else {
2939
2940 #ifdef CONFIG_FB_SIS_315
2941         ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2942         temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2943         SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
2944         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2945         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2946         temp2 |= 0x01;
2947         SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2948         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2949         temp2 ^= 0x01;
2950         SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
2951         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2952         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2953         SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
2954         temp1 = 0;
2955         if(temp2 & 0x02) temp1 |= 0x01;
2956         if(temp2 & 0x10) temp1 |= 0x01;
2957         if(temp2 & 0x04) temp1 |= 0x02;
2958         if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2959         switch(temp1) {
2960         case 0x01:
2961              printk(KERN_INFO "%s CVBS output\n", stdstr);
2962              ivideo->vbflags |= TV_AVIDEO;
2963              orSISIDXREG(SISCR, 0x32, 0x01);
2964              andSISIDXREG(SISCR, 0x32, ~0x06);
2965              break;
2966         case 0x02:
2967              printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2968              ivideo->vbflags |= TV_SVIDEO;
2969              orSISIDXREG(SISCR, 0x32, 0x02);
2970              andSISIDXREG(SISCR, 0x32, ~0x05);
2971              break;
2972         case 0x04:
2973              printk(KERN_INFO "%s SCART output\n", stdstr);
2974              orSISIDXREG(SISCR, 0x32, 0x04);
2975              andSISIDXREG(SISCR, 0x32, ~0x03);
2976              break;
2977         default:
2978              andSISIDXREG(SISCR, 0x32, ~0x07);
2979         }
2980 #endif
2981     }
2982 }
2983
2984 /* ------------------------ Heap routines -------------------------- */
2985
2986 static u32 __devinit
2987 sisfb_getheapstart(struct sis_video_info *ivideo)
2988 {
2989         u32 ret = ivideo->sisfb_parm_mem * 1024;
2990         u32 max = ivideo->video_size - ivideo->hwcursor_size;
2991         u32 def;
2992
2993         /* Calculate heap start = end of memory for console
2994          *
2995          * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
2996          * C = console, D = heap, H = HWCursor, Q = cmd-queue
2997          *
2998          * Basically given by "mem" parameter
2999          *
3000          * maximum = videosize - cmd_queue - hwcursor
3001          *           (results in a heap of size 0)
3002          * default = SiS 300: depends on videosize
3003          *           SiS 315/330: 32k below max
3004          */
3005
3006         if(ivideo->sisvga_engine == SIS_300_VGA) {
3007            max -= TURBO_QUEUE_AREA_SIZE;
3008            if(ivideo->video_size > 0x1000000) {
3009               def = 0xc00000;
3010            } else if(ivideo->video_size > 0x800000) {
3011               def = 0x800000;
3012            } else {
3013               def = 0x400000;
3014            }
3015         } else {
3016            max -= COMMAND_QUEUE_AREA_SIZE;
3017            def = max - 0x8000;
3018         }
3019
3020         if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
3021            ret = def;
3022         }
3023
3024         return ret;
3025 }
3026
3027 static int __devinit
3028 sisfb_heap_init(struct sis_video_info *ivideo)
3029 {
3030      SIS_OH *poh;
3031
3032      ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
3033
3034      ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3035      ivideo->sisfb_heap_end   = ivideo->video_vbase + ivideo->video_size;
3036
3037      /* Initialize command queue (We use MMIO only) */
3038
3039 #ifdef CONFIG_FB_SIS_315
3040      if(ivideo->sisvga_engine == SIS_315_VGA) {
3041         u32 tempq = 0;
3042         u8  temp = 0;
3043
3044         ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
3045
3046         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
3047         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3048
3049         tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3050         MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3051
3052         temp = SIS_CMD_QUEUE_SIZE_512k;
3053         temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3054         outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3055
3056         tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
3057         MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3058
3059         ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3060      }
3061 #endif
3062
3063 #ifdef CONFIG_FB_SIS_300
3064      if(ivideo->sisvga_engine == SIS_300_VGA) {
3065         unsigned long tqueue_pos;
3066         u8 tq_state;
3067
3068         ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
3069
3070         tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
3071
3072         inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3073         tq_state |= 0xf0;
3074         tq_state &= 0xfc;
3075         tq_state |= (u8)(tqueue_pos >> 8);
3076         outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
3077
3078         outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
3079
3080         ivideo->caps |= TURBO_QUEUE_CAP;
3081      }
3082 #endif
3083
3084      /* Reserve memory for the HWCursor */
3085      ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
3086      ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
3087      ivideo->caps |= HW_CURSOR_CAP;
3088
3089      ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
3090
3091      if(ivideo->cardnumber == 0) {
3092
3093         printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3094                 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3095
3096         sisfb_heap.vinfo = ivideo;
3097
3098         sisfb_heap.poha_chain = NULL;
3099         sisfb_heap.poh_freelist = NULL;
3100
3101         poh = sisfb_poh_new_node();
3102         if(poh == NULL) return 1;
3103
3104         poh->poh_next = &sisfb_heap.oh_free;
3105         poh->poh_prev = &sisfb_heap.oh_free;
3106         poh->size = ivideo->sisfb_heap_size;
3107         poh->offset = ivideo->heapstart;
3108
3109         sisfb_heap.oh_free.poh_next = poh;
3110         sisfb_heap.oh_free.poh_prev = poh;
3111         sisfb_heap.oh_free.size = 0;
3112         sisfb_heap.max_freesize = poh->size;
3113
3114         sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
3115         sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
3116         sisfb_heap.oh_used.size = SENTINEL;
3117
3118      } else {
3119
3120         printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
3121
3122      }
3123
3124      return 0;
3125 }
3126
3127 static SIS_OH *
3128 sisfb_poh_new_node(void)
3129 {
3130         int           i;
3131         unsigned long cOhs;
3132         SIS_OHALLOC   *poha;
3133         SIS_OH        *poh;
3134
3135         if(sisfb_heap.poh_freelist == NULL) {
3136                 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3137                 if(!poha) return NULL;
3138
3139                 poha->poha_next = sisfb_heap.poha_chain;
3140                 sisfb_heap.poha_chain = poha;
3141
3142                 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
3143
3144                 poh = &poha->aoh[0];
3145                 for(i = cOhs - 1; i != 0; i--) {
3146                         poh->poh_next = poh + 1;
3147                         poh = poh + 1;
3148                 }
3149
3150                 poh->poh_next = NULL;
3151                 sisfb_heap.poh_freelist = &poha->aoh[0];
3152         }
3153
3154         poh = sisfb_heap.poh_freelist;
3155         sisfb_heap.poh_freelist = poh->poh_next;
3156
3157         return (poh);
3158 }
3159
3160 static SIS_OH *
3161 sisfb_poh_allocate(u32 size)
3162 {
3163         SIS_OH *pohThis;
3164         SIS_OH *pohRoot;
3165         int     bAllocated = 0;
3166
3167         if(size > sisfb_heap.max_freesize) {
3168                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3169                         (unsigned int) size / 1024);
3170                 return (NULL);
3171         }
3172
3173         pohThis = sisfb_heap.oh_free.poh_next;
3174
3175         while(pohThis != &sisfb_heap.oh_free) {
3176                 if (size <= pohThis->size) {
3177                         bAllocated = 1;
3178                         break;
3179                 }
3180                 pohThis = pohThis->poh_next;
3181         }
3182
3183         if(!bAllocated) {
3184                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3185                         (unsigned int) size / 1024);
3186                 return (NULL);
3187         }
3188
3189         if(size == pohThis->size) {
3190                 pohRoot = pohThis;
3191                 sisfb_delete_node(pohThis);
3192         } else {
3193                 pohRoot = sisfb_poh_new_node();
3194
3195                 if(pohRoot == NULL) {
3196                         return (NULL);
3197                 }
3198
3199                 pohRoot->offset = pohThis->offset;
3200                 pohRoot->size = size;
3201
3202                 pohThis->offset += size;
3203                 pohThis->size -= size;
3204         }
3205
3206         sisfb_heap.max_freesize -= size;
3207
3208         pohThis = &sisfb_heap.oh_used;
3209         sisfb_insert_node(pohThis, pohRoot);
3210
3211         return (pohRoot);
3212 }
3213
3214 static void
3215 sisfb_delete_node(SIS_OH *poh)
3216 {
3217         SIS_OH *poh_prev;
3218         SIS_OH *poh_next;
3219
3220         poh_prev = poh->poh_prev;
3221         poh_next = poh->poh_next;
3222
3223         poh_prev->poh_next = poh_next;
3224         poh_next->poh_prev = poh_prev;
3225 }
3226
3227 static void
3228 sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
3229 {
3230         SIS_OH *pohTemp;
3231
3232         pohTemp = pohList->poh_next;
3233
3234         pohList->poh_next = poh;
3235         pohTemp->poh_prev = poh;
3236
3237         poh->poh_prev = pohList;
3238         poh->poh_next = pohTemp;
3239 }
3240
3241 static SIS_OH *
3242 sisfb_poh_free(u32 base)
3243 {
3244         SIS_OH *pohThis;
3245         SIS_OH *poh_freed;
3246         SIS_OH *poh_prev;
3247         SIS_OH *poh_next;
3248         u32     ulUpper;
3249         u32     ulLower;
3250         int     foundNode = 0;
3251
3252         poh_freed = sisfb_heap.oh_used.poh_next;
3253
3254         while(poh_freed != &sisfb_heap.oh_used) {
3255                 if(poh_freed->offset == base) {
3256                         foundNode = 1;
3257                         break;
3258                 }
3259
3260                 poh_freed = poh_freed->poh_next;
3261         }
3262
3263         if(!foundNode) return(NULL);
3264
3265         sisfb_heap.max_freesize += poh_freed->size;
3266
3267         poh_prev = poh_next = NULL;
3268         ulUpper = poh_freed->offset + poh_freed->size;
3269         ulLower = poh_freed->offset;
3270
3271         pohThis = sisfb_heap.oh_free.poh_next;
3272
3273         while(pohThis != &sisfb_heap.oh_free) {
3274                 if(pohThis->offset == ulUpper) {
3275                         poh_next = pohThis;
3276                 } else if((pohThis->offset + pohThis->size) == ulLower) {
3277                         poh_prev = pohThis;
3278                 }
3279                 pohThis = pohThis->poh_next;
3280         }
3281
3282         sisfb_delete_node(poh_freed);
3283
3284         if(poh_prev && poh_next) {
3285                 poh_prev->size += (poh_freed->size + poh_next->size);
3286                 sisfb_delete_node(poh_next);
3287                 sisfb_free_node(poh_freed);
3288                 sisfb_free_node(poh_next);
3289                 return(poh_prev);
3290         }
3291
3292         if(poh_prev) {
3293                 poh_prev->size += poh_freed->size;
3294                 sisfb_free_node(poh_freed);
3295                 return(poh_prev);
3296         }
3297
3298         if(poh_next) {
3299                 poh_next->size += poh_freed->size;
3300                 poh_next->offset = poh_freed->offset;
3301                 sisfb_free_node(poh_freed);
3302                 return(poh_next);
3303         }
3304
3305         sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
3306
3307         return(poh_freed);
3308 }
3309
3310 static void
3311 sisfb_free_node(SIS_OH *poh)
3312 {
3313         if(poh == NULL) return;
3314
3315         poh->poh_next = sisfb_heap.poh_freelist;
3316         sisfb_heap.poh_freelist = poh;
3317 }
3318
3319 void
3320 sis_malloc(struct sis_memreq *req)
3321 {
3322         struct sis_video_info *ivideo = sisfb_heap.vinfo;
3323         SIS_OH *poh = NULL;
3324
3325         if((ivideo) && (!ivideo->havenoheap)) {
3326            poh = sisfb_poh_allocate((u32)req->size);
3327         }
3328
3329         if(poh == NULL) {
3330            req->offset = req->size = 0;
3331            DPRINTK("sisfb: Video RAM allocation failed\n");
3332         } else {
3333            req->offset = poh->offset;
3334            req->size = poh->size;
3335            DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3336                     (poh->offset + ivideo->video_vbase));
3337         }
3338 }
3339
3340 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3341
3342 void
3343 sis_free(u32 base)
3344 {
3345         struct sis_video_info *ivideo = sisfb_heap.vinfo;
3346         SIS_OH *poh;
3347
3348         if((!ivideo) || (ivideo->havenoheap)) return;
3349
3350         poh = sisfb_poh_free((u32)base);
3351
3352         if(poh == NULL) {
3353                 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3354                         (unsigned int) base);
3355         }
3356 }
3357
3358 /* --------------------- SetMode routines ------------------------- */
3359
3360 static void
3361 sisfb_pre_setmode(struct sis_video_info *ivideo)
3362 {
3363         u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3364         int tvregnum = 0;
3365
3366         ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3367
3368         inSISIDXREG(SISCR, 0x31, cr31);
3369         cr31 &= ~0x60;
3370         cr31 |= 0x04;
3371
3372         cr33 = ivideo->rate_idx & 0x0F;
3373
3374 #ifdef CONFIG_FB_SIS_315
3375         if(ivideo->sisvga_engine == SIS_315_VGA) {
3376            if(ivideo->chip >= SIS_661) {
3377               inSISIDXREG(SISCR, 0x38, cr38);
3378               cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3379            } else {
3380               tvregnum = 0x38;
3381               inSISIDXREG(SISCR, tvregnum, cr38);
3382               cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3383            }
3384         }
3385 #endif
3386 #ifdef CONFIG_FB_SIS_300
3387         if(ivideo->sisvga_engine == SIS_300_VGA) {
3388            tvregnum = 0x35;
3389            inSISIDXREG(SISCR, tvregnum, cr38);
3390         }
3391 #endif
3392
3393         SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3394         SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3395
3396         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3397
3398            case CRT2_TV:
3399               cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3400               if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
3401 #ifdef CONFIG_FB_SIS_315
3402                  if(ivideo->chip >= SIS_661) {
3403                     cr38 |= 0x04;
3404                     if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3405                     else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3406                     else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3407                     cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3408                     cr35 &= ~0x01;
3409                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3410                  } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3411                     cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3412                     cr38 |= 0x08;
3413                     if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3414                     else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3415                     else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3416                     cr31 &= ~0x01;
3417                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3418                  }
3419 #endif
3420               } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
3421                  if(ivideo->chip >= SIS_661) {
3422                     cr38 |= 0x04;
3423                     cr35 |= 0x60;
3424                  } else {
3425                     cr30 |= 0x80;
3426                  }
3427                  cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3428                  cr31 |= 0x01;
3429                  cr35 |= 0x01;
3430                  ivideo->currentvbflags |= TV_HIVISION;
3431               } else if(ivideo->vbflags & TV_SCART) {
3432                  cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3433                  cr31 |= 0x01;
3434                  cr35 |= 0x01;
3435                  ivideo->currentvbflags |= TV_SCART;
3436               } else {
3437                  if(ivideo->vbflags & TV_SVIDEO) {
3438                     cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3439                     ivideo->currentvbflags |= TV_SVIDEO;
3440                  }
3441                  if(ivideo->vbflags & TV_AVIDEO) {
3442                     cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3443                     ivideo->currentvbflags |= TV_AVIDEO;
3444                  }
3445               }
3446               cr31 |= SIS_DRIVER_MODE;
3447
3448               if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
3449                  if(ivideo->vbflags & TV_PAL) {
3450                     cr31 |= 0x01; cr35 |= 0x01;
3451                     ivideo->currentvbflags |= TV_PAL;
3452                     if(ivideo->vbflags & TV_PALM) {
3453                        cr38 |= 0x40; cr35 |= 0x04;
3454                        ivideo->currentvbflags |= TV_PALM;
3455                     } else if(ivideo->vbflags & TV_PALN) {
3456                        cr38 |= 0x80; cr35 |= 0x08;
3457                        ivideo->currentvbflags |= TV_PALN;
3458                     }
3459                  } else {
3460                     cr31 &= ~0x01; cr35 &= ~0x01;
3461                     ivideo->currentvbflags |= TV_NTSC;
3462                     if(ivideo->vbflags & TV_NTSCJ) {
3463                        cr38 |= 0x40; cr35 |= 0x02;
3464                        ivideo->currentvbflags |= TV_NTSCJ;
3465                     }
3466                  }
3467               }
3468               break;
3469
3470            case CRT2_LCD:
3471               cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3472               cr31 |= SIS_DRIVER_MODE;
3473               SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3474               SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3475               break;
3476
3477            case CRT2_VGA:
3478               cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3479               cr31 |= SIS_DRIVER_MODE;
3480               if(ivideo->sisfb_nocrt2rate) {
3481                  cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3482               } else {
3483                  cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3484               }
3485               break;
3486
3487            default:     /* disable CRT2 */
3488               cr30 = 0x00;
3489               cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3490         }
3491
3492         outSISIDXREG(SISCR, 0x30, cr30);
3493         outSISIDXREG(SISCR, 0x33, cr33);
3494
3495         if(ivideo->chip >= SIS_661) {
3496 #ifdef CONFIG_FB_SIS_315
3497            cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3498            setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3499            cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3500            setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3501 #endif
3502         } else if(ivideo->chip != SIS_300) {
3503            outSISIDXREG(SISCR, tvregnum, cr38);
3504         }
3505         outSISIDXREG(SISCR, 0x31, cr31);
3506
3507         if(ivideo->accel) sisfb_syncaccel(ivideo);
3508
3509         ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3510 }
3511
3512 /* Fix SR11 for 661 and later */
3513 #ifdef CONFIG_FB_SIS_315
3514 static void
3515 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3516 {
3517     u8  tmpreg;
3518
3519     if(ivideo->chip >= SIS_661) {
3520        inSISIDXREG(SISSR,0x11,tmpreg);
3521        if(tmpreg & 0x20) {
3522           inSISIDXREG(SISSR,0x3e,tmpreg);
3523           tmpreg = (tmpreg + 1) & 0xff;
3524           outSISIDXREG(SISSR,0x3e,tmpreg);
3525           inSISIDXREG(SISSR,0x11,tmpreg);
3526        }
3527        if(tmpreg & 0xf0) {
3528           andSISIDXREG(SISSR,0x11,0x0f);
3529        }
3530     }
3531 }
3532 #endif
3533
3534 static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3535 {
3536    if(val > 32) val = 32;
3537    if(val < -32) val = -32;
3538    ivideo->tvxpos = val;
3539
3540    if(ivideo->sisfblocked) return;
3541    if(!ivideo->modechanged) return;
3542
3543    if(ivideo->currentvbflags & CRT2_TV) {
3544
3545       if(ivideo->vbflags & VB_CHRONTEL) {
3546
3547          int x = ivideo->tvx;
3548
3549          switch(ivideo->chronteltype) {
3550          case 1:
3551              x += val;
3552              if(x < 0) x = 0;
3553              outSISIDXREG(SISSR,0x05,0x86);
3554              SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
3555              SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
3556              break;
3557          case 2:
3558              /* Not supported by hardware */
3559              break;
3560          }
3561
3562       } else if(ivideo->vbflags & VB_SISBRIDGE) {
3563
3564          u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3565          unsigned short temp;
3566
3567          p2_1f = ivideo->p2_1f;
3568          p2_20 = ivideo->p2_20;
3569          p2_2b = ivideo->p2_2b;
3570          p2_42 = ivideo->p2_42;
3571          p2_43 = ivideo->p2_43;
3572
3573          temp = p2_1f | ((p2_20 & 0xf0) << 4);
3574          temp += (val * 2);
3575          p2_1f = temp & 0xff;
3576          p2_20 = (temp & 0xf00) >> 4;
3577          p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3578          temp = p2_43 | ((p2_42 & 0xf0) << 4);
3579          temp += (val * 2);
3580          p2_43 = temp & 0xff;
3581          p2_42 = (temp & 0xf00) >> 4;
3582          outSISIDXREG(SISPART2,0x1f,p2_1f);
3583          setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3584          setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3585          setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3586          outSISIDXREG(SISPART2,0x43,p2_43);
3587       }
3588    }
3589 }
3590
3591 static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3592 {
3593    if(val > 32) val = 32;
3594    if(val < -32) val = -32;
3595    ivideo->tvypos = val;
3596
3597    if(ivideo->sisfblocked) return;
3598    if(!ivideo->modechanged) return;
3599
3600    if(ivideo->currentvbflags & CRT2_TV) {
3601
3602       if(ivideo->vbflags & VB_CHRONTEL) {
3603
3604          int y = ivideo->tvy;
3605
3606          switch(ivideo->chronteltype) {
3607          case 1:
3608             y -= val;
3609             if(y < 0) y = 0;
3610             outSISIDXREG(SISSR,0x05,0x86);
3611             SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
3612             SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
3613             break;
3614          case 2:
3615             /* Not supported by hardware */
3616             break;
3617          }
3618
3619       } else if(ivideo->vbflags & VB_SISBRIDGE) {
3620
3621          char p2_01, p2_02;
3622          val /= 2;
3623          p2_01 = ivideo->p2_01;
3624          p2_02 = ivideo->p2_02;
3625
3626          p2_01 += val;
3627          p2_02 += val;
3628          while((p2_01 <= 0) || (p2_02 <= 0)) {
3629             p2_01 += 2;
3630             p2_02 += 2;
3631          }
3632          outSISIDXREG(SISPART2,0x01,p2_01);
3633          outSISIDXREG(SISPART2,0x02,p2_02);
3634       }
3635    }
3636 }
3637
3638 static void
3639 sisfb_post_setmode(struct sis_video_info *ivideo)
3640 {
3641         BOOLEAN crt1isoff = FALSE;
3642         BOOLEAN doit = TRUE;
3643 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3644         u8 reg;
3645 #endif
3646 #ifdef CONFIG_FB_SIS_315
3647         u8 reg1;
3648 #endif
3649
3650         outSISIDXREG(SISSR,0x05,0x86);
3651
3652 #ifdef CONFIG_FB_SIS_315
3653         sisfb_fixup_SR11(ivideo);
3654 #endif
3655
3656         /* Now we actually HAVE changed the display mode */
3657         ivideo->modechanged = 1;
3658
3659         /* We can't switch off CRT1 if bridge is in slave mode */
3660         if(ivideo->vbflags & VB_VIDEOBRIDGE) {
3661                 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3662         } else ivideo->sisfb_crt1off = 0;
3663
3664 #ifdef CONFIG_FB_SIS_300
3665         if(ivideo->sisvga_engine == SIS_300_VGA) {
3666            if((ivideo->sisfb_crt1off) && (doit)) {
3667                 crt1isoff = TRUE;
3668                 reg = 0x00;
3669            } else {
3670                 crt1isoff = FALSE;
3671                 reg = 0x80;
3672            }
3673            setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3674         }
3675 #endif
3676 #ifdef CONFIG_FB_SIS_315
3677         if(ivideo->sisvga_engine == SIS_315_VGA) {
3678            if((ivideo->sisfb_crt1off) && (doit)) {
3679                 crt1isoff = TRUE;
3680                 reg  = 0x40;
3681                 reg1 = 0xc0;
3682            } else {
3683                 crt1isoff = FALSE;
3684                 reg  = 0x00;
3685                 reg1 = 0x00;
3686
3687            }
3688            setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3689            setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3690         }
3691 #endif
3692
3693         if(crt1isoff) {
3694            ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3695            ivideo->currentvbflags |= VB_SINGLE_MODE;
3696         } else {
3697            ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3698            if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3699                 ivideo->currentvbflags |= VB_MIRROR_MODE;
3700            } else {
3701                 ivideo->currentvbflags |= VB_SINGLE_MODE;
3702            }
3703         }
3704
3705         andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3706
3707         if(ivideo->currentvbflags & CRT2_TV) {
3708            if(ivideo->vbflags & VB_SISBRIDGE) {
3709               inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3710               inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3711               inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3712               inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3713               inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3714               inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3715               inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3716            } else if(ivideo->vbflags & VB_CHRONTEL) {
3717               if(ivideo->chronteltype == 1) {
3718                  ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3719                  ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3720                  ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3721                  ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3722               }
3723            }
3724         }
3725
3726         if(ivideo->tvxpos) {
3727            sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3728         }
3729         if(ivideo->tvypos) {
3730            sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3731         }
3732
3733         if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) {  /* Set filter for SiS301 */
3734
3735                 unsigned char filter_tb = 0;
3736
3737                 switch (ivideo->video_width) {
3738                    case 320:
3739                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
3740                         break;
3741                    case 640:
3742                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
3743                         break;
3744                    case 720:
3745                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
3746                         break;
3747                    case 400:
3748                    case 800:
3749                         filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
3750                         break;
3751                    default:
3752                         ivideo->sisfb_filter = -1;
3753                         break;
3754                 }
3755
3756                 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
3757
3758                 if(ivideo->vbflags & TV_NTSC) {
3759
3760                         andSISIDXREG(SISPART2, 0x3a, 0x1f);
3761
3762                         if (ivideo->vbflags & TV_SVIDEO) {
3763
3764                                 andSISIDXREG(SISPART2, 0x30, 0xdf);
3765
3766                         } else if (ivideo->vbflags & TV_AVIDEO) {
3767
3768                                 orSISIDXREG(SISPART2, 0x30, 0x20);
3769
3770                                 switch (ivideo->video_width) {
3771                                 case 640:
3772                                         outSISIDXREG(SISPART2, 0x35, 0xEB);
3773                                         outSISIDXREG(SISPART2, 0x36, 0x04);
3774                                         outSISIDXREG(SISPART2, 0x37, 0x25);
3775                                         outSISIDXREG(SISPART2, 0x38, 0x18);
3776                                         break;
3777                                 case 720:
3778                                         outSISIDXREG(SISPART2, 0x35, 0xEE);
3779                                         outSISIDXREG(SISPART2, 0x36, 0x0C);
3780                                         outSISIDXREG(SISPART2, 0x37, 0x22);
3781                                         outSISIDXREG(SISPART2, 0x38, 0x08);
3782                                         break;
3783                                 case 400:
3784                                 case 800:
3785                                         outSISIDXREG(SISPART2, 0x35, 0xEB);
3786                                         outSISIDXREG(SISPART2, 0x36, 0x15);
3787                                         outSISIDXREG(SISPART2, 0x37, 0x25);
3788                                         outSISIDXREG(SISPART2, 0x38, 0xF6);
3789                                         break;
3790                                 }
3791                         }
3792
3793                 } else if(ivideo->vbflags & TV_PAL) {
3794
3795                         andSISIDXREG(SISPART2, 0x3A, 0x1F);
3796
3797                         if (ivideo->vbflags & TV_SVIDEO) {
3798
3799                                 andSISIDXREG(SISPART2, 0x30, 0xDF);
3800
3801                         } else if (ivideo->vbflags & TV_AVIDEO) {
3802
3803                                 orSISIDXREG(SISPART2, 0x30, 0x20);
3804
3805                                 switch (ivideo->video_width) {
3806                                 case 640:
3807                                         outSISIDXREG(SISPART2, 0x35, 0xF1);
3808                                         outSISIDXREG(SISPART2, 0x36, 0xF7);
3809                                         outSISIDXREG(SISPART2, 0x37, 0x1F);
3810                                         outSISIDXREG(SISPART2, 0x38, 0x32);
3811                                         break;
3812                                 case 720:
3813                                         outSISIDXREG(SISPART2, 0x35, 0xF3);
3814                                         outSISIDXREG(SISPART2, 0x36, 0x00);
3815                                         outSISIDXREG(SISPART2, 0x37, 0x1D);
3816                                         outSISIDXREG(SISPART2, 0x38, 0x20);
3817                                         break;
3818                                 case 400:
3819                                 case 800:
3820                                         outSISIDXREG(SISPART2, 0x35, 0xFC);
3821                                         outSISIDXREG(SISPART2, 0x36, 0xFB);
3822                                         outSISIDXREG(SISPART2, 0x37, 0x14);
3823                                         outSISIDXREG(SISPART2, 0x38, 0x2A);
3824                                         break;
3825                                 }
3826                         }
3827                 }
3828
3829                 if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
3830                    outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
3831                    outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
3832                    outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
3833                    outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
3834                 }
3835           
3836         }
3837 }
3838
3839 #ifndef MODULE
3840 int __init sisfb_setup(char *options)
3841 {
3842         char *this_opt;
3843         
3844         sisfb_setdefaultparms();
3845
3846         printk(KERN_DEBUG "sisfb: Options %s\n", options);
3847
3848         if(!options || !(*options)) {
3849                 return 0;
3850         }
3851
3852         while((this_opt = strsep(&options, ",")) != NULL) {
3853
3854                 if(!(*this_opt)) continue;
3855
3856                 if(!strnicmp(this_opt, "off", 3)) {
3857                         sisfb_off = 1;
3858                 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3859                         /* Need to check crt2 type first for fstn/dstn */
3860                         sisfb_search_crt2type(this_opt + 14);
3861                 } else if(!strnicmp(this_opt, "tvmode:",7)) {
3862                         sisfb_search_tvstd(this_opt + 7);
3863                 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3864                         sisfb_search_tvstd(this_opt + 7);
3865                 } else if(!strnicmp(this_opt, "mode:", 5)) {
3866                         sisfb_search_mode(this_opt + 5, FALSE);
3867                 } else if(!strnicmp(this_opt, "vesa:", 5)) {
3868                         sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
3869 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
3870                 } else if(!strnicmp(this_opt, "inverse", 7)) {
3871                         sisfb_inverse = 1;
3872                         /* fb_invert_cmaps(); */
3873                 } else if(!strnicmp(this_opt, "font:", 5)) {
3874                         if(strlen(this_opt + 5) < 40) {
3875                            strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
3876                            sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
3877                         }
3878 #endif
3879                 } else if(!strnicmp(this_opt, "rate:", 5)) {
3880                         sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3881                 } else if(!strnicmp(this_opt, "filter:", 7)) {
3882                         sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
3883                 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3884                         sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3885                 } else if(!strnicmp(this_opt, "mem:",4)) {
3886                         sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
3887                 } else if(!strnicmp(this_opt, "pdc:", 4)) {
3888                         sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
3889                 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
3890                         sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
3891                 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3892                         sisfb_accel = 0;
3893                 } else if(!strnicmp(this_opt, "accel", 5)) {
3894                         sisfb_accel = -1;
3895                 } else if(!strnicmp(this_opt, "noypan", 6)) {
3896                         sisfb_ypan = 0;
3897                 } else if(!strnicmp(this_opt, "ypan", 4)) {
3898                         sisfb_ypan = -1;
3899                 } else if(!strnicmp(this_opt, "nomax", 5)) {
3900                         sisfb_max = 0;
3901                 } else if(!strnicmp(this_opt, "max", 3)) {
3902                         sisfb_max = -1;
3903                 } else if(!strnicmp(this_opt, "userom:", 7)) {
3904                         sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3905                 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3906                         sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3907                 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3908                         sisfb_nocrt2rate = 1;
3909                 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
3910                         unsigned long temp = 2;
3911                         temp = simple_strtoul(this_opt + 9, NULL, 0);
3912                         if((temp == 0) || (temp == 1)) {
3913                            sisfb_scalelcd = temp ^ 1;
3914                         }
3915                 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
3916                         int temp = 0;
3917                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3918                         if((temp >= -32) && (temp <= 32)) {
3919                            sisfb_tvxposoffset = temp;
3920                         }
3921                 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
3922                         int temp = 0;
3923                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
3924                         if((temp >= -32) && (temp <= 32)) {
3925                            sisfb_tvyposoffset = temp;
3926                         }
3927                 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
3928                         sisfb_search_specialtiming(this_opt + 14);
3929                 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
3930                         int temp = 4;
3931                         temp = simple_strtoul(this_opt + 7, NULL, 0);
3932                         if((temp >= 0) && (temp <= 3)) {
3933                            sisfb_lvdshl = temp;
3934                         }
3935                 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
3936                         sisfb_search_mode(this_opt, TRUE);
3937 #if !defined(__i386__) && !defined(__x86_64__)
3938                 } else if(!strnicmp(this_opt, "resetcard", 9)) {
3939                         sisfb_resetcard = 1;
3940                 } else if(!strnicmp(this_opt, "videoram:", 9)) {
3941                         sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
3942 #endif
3943                 } else {
3944                         printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
3945                 }
3946
3947         }
3948
3949
3950
3951         return 0;
3952 }
3953 #endif
3954
3955 static void __iomem * __devinit sis_find_rom(struct pci_dev *pdev)
3956 {
3957         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3958
3959 #if defined(__i386__) || defined(__x86_64__)
3960         u32  segstart;
3961         void __iomem *rom_base, *rom;
3962         int  romptr;
3963         unsigned short pciid;
3964
3965         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
3966
3967             rom_base = ioremap(segstart, 0x10000);
3968             if(!rom_base) continue;
3969
3970             if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
3971                iounmap(rom_base);
3972                continue;
3973             }
3974
3975             romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
3976             if(romptr > (0x10000 - 8)) {
3977                iounmap(rom_base);
3978                continue;
3979             }
3980
3981             rom = rom_base + romptr;
3982
3983             if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
3984                (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
3985                iounmap(rom_base);
3986                continue;
3987             }
3988
3989             pciid = readb(rom + 4) | (readb(rom + 5) << 8);
3990             if(pciid != 0x1039) {
3991                iounmap(rom_base);
3992                continue;
3993             }
3994
3995             pciid = readb(rom + 6) | (readb(rom + 7) << 8);
3996             if(pciid == ivideo->chip_id) return rom_base;
3997
3998             iounmap(rom_base);
3999         }
4000 #else
4001         void __iomem *rom_base, *rom, *myrombase = NULL;
4002         int  romptr;
4003         unsigned short pciid;
4004         u32 backup;
4005
4006         pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup);
4007         pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4008                         (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4009
4010         rom_base = ioremap(ivideo->video_base, 65536);
4011         if(rom_base) {
4012            if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
4013               romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4014               if(romptr <= (0x10000 - 8)) {
4015                  rom = rom_base + romptr;
4016                  if((readb(rom)     == 'P') && (readb(rom + 1) == 'C') &&
4017                     (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
4018                     pciid = readb(rom + 4) | (readb(rom + 5) << 8);
4019                     if(pciid == 0x1039) {
4020                        pciid = readb(rom + 6) | (readb(rom + 7) << 8);
4021                        if(pciid == ivideo->chip_id) {
4022                           if((myrombase = vmalloc(65536))) {
4023                              memcpy_fromio(myrombase, rom_base, 65536);
4024                           }
4025                        }
4026                     }
4027                  }
4028               }
4029            }
4030            iounmap(rom_base);
4031         }
4032         pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup);
4033         if(myrombase) return myrombase;
4034 #endif
4035         return NULL;
4036 }
4037
4038 #ifdef CONFIG_FB_SIS_300
4039 static int __devinit
4040 sisfb_chkbuswidth300(struct pci_dev *pdev, void __iomem *FBAddress)
4041 {
4042         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4043         int i, j;
4044         USHORT temp;
4045         UCHAR reg;
4046
4047         andSISIDXREG(SISSR,0x15,0xFB);
4048         orSISIDXREG(SISSR,0x15,0x04);
4049         outSISIDXREG(SISSR,0x13,0x00);
4050         outSISIDXREG(SISSR,0x14,0xBF);
4051
4052         for(i=0; i<2; i++) {
4053            temp = 0x1234;
4054            for(j=0; j<4; j++) {
4055               writew(temp, FBAddress);
4056               if(readw(FBAddress) == temp) break;
4057               orSISIDXREG(SISSR,0x3c,0x01);
4058               inSISIDXREG(SISSR,0x05,reg);
4059               inSISIDXREG(SISSR,0x05,reg);
4060               andSISIDXREG(SISSR,0x3c,0xfe);
4061               inSISIDXREG(SISSR,0x05,reg);
4062               inSISIDXREG(SISSR,0x05,reg);
4063               temp++;
4064            }
4065         }
4066
4067         writel(0x01234567L, FBAddress);
4068         writel(0x456789ABL, (FBAddress+4));
4069         writel(0x89ABCDEFL, (FBAddress+8));
4070         writel(0xCDEF0123L, (FBAddress+12));
4071         inSISIDXREG(SISSR,0x3b,reg);
4072         if(reg & 0x01) {
4073            if(readl((FBAddress+12)) == 0xCDEF0123L) return(4);  /* Channel A 128bit */
4074         }
4075         if(readl((FBAddress+4)) == 0x456789ABL)     return(2);  /* Channel B 64bit */
4076         return(1);                                              /* 32bit */
4077 }
4078
4079 static void __devinit
4080 sisfb_setramsize300(struct pci_dev *pdev)
4081 {
4082         struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
4083         void __iomem *FBAddr = ivideo->sishw_ext.pjVideoMemoryAddress, *Addr;
4084         USHORT  SR13, SR14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
4085         int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
4086         int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
4087         int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
4088         const   USHORT SiS_DRAMType[17][5] = {
4089                         {0x0C,0x0A,0x02,0x40,0x39},
4090                         {0x0D,0x0A,0x01,0x40,0x48},
4091                         {0x0C,0x09,0x02,0x20,0x35},
4092                         {0x0D,0x09,0x01,0x20,0x44},
4093                         {0x0C,0x08,0x02,0x10,0x31},
4094                         {0x0D,0x08,0x01,0x10,0x40},
4095                         {0x0C,0x0A,0x01,0x20,0x34},
4096                         {0x0C,0x09,0x01,0x08,0x32},
4097                         {0x0B,0x08,0x02,0x08,0x21},
4098                         {0x0C,0x08,0x01,0x08,0x30},
4099                         {0x0A,0x08,0x02,0x04,0x11},
4100                         {0x0B,0x0A,0x01,0x10,0x28},
4101                         {0x09,0x08,0x02,0x02,0x01},
4102                         {0x0B,0x09,0x01,0x08,0x24},
4103                         {0x0B,0x08,0x01,0x04,0x20},
4104                         {0x0A,0x08,0x01,0x02,0x10},
4105                         {0x09,0x08,0x01,0x01,0x00}
4106                 };
4107
4108         buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
4109
4110         MB2Bank = 16;
4111         Done = 0;
4112         for(i = 6; i >= 0; i--) {
4113            if(Done) break;
4114            PseudoRankCapacity = 1 << i;
4115            for(j = 4; j >= 1; j--) {
4116               if(Done) break;
4117               PseudoTotalCapacity = PseudoRankCapacity * j;
4118               PseudoAdrPinCount = 15 - j;
4119               if(PseudoTotalCapacity <= 64) {
4120                  for(k = 0; k <= 16; k++) {
4121                     if(Done) break;
4122                     RankCapacity = buswidth * SiS_DRAMType[k][3];
4123                     AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
4124                     if(RankCapacity == PseudoRankCapacity)
4125                        if(AdrPinCount <= PseudoAdrPinCount) {
4126                           if(j == 3) {             /* Rank No */
4127                              BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
4128                              BankNumMid  = RankCapacity * MB2Bank * 1 - 1;
4129                           } else {
4130                              BankNumHigh = RankCapacity * MB2Bank * j - 1;
4131                              BankNumMid  = RankCapacity * MB2Bank * j / 2 - 1;
4132                           }
4133                           PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4134                           PhysicalAdrHigh = BankNumHigh;
4135                           PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4136                           PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4137                           /* Write data */
4138                           andSISIDXREG(SISSR,0x15,0xFB); /* Test */
4139                           orSISIDXREG(SISSR,0x15,0x04);  /* Test */
4140                           TotalCapacity = SiS_DRAMType[k][3] * buswidth;
4141                           SR13 = SiS_DRAMType[k][4];
4142                           if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
4143                           if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
4144                           if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
4145                           outSISIDXREG(SISSR,0x13,SR13);
4146                           outSISIDXREG(SISSR,0x14,SR14);
4147                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4148                           /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
4149                           writew(((USHORT)PhysicalAdrHigh), Addr);
4150                           Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
4151                           /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
4152                           writew(((USHORT)BankNumMid), Addr);
4153                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
4154                           /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
4155                           writew(((USHORT)PhysicalAdrHalfPage), Addr);
4156                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
4157                           /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
4158                           writew(((USHORT)PhysicalAdrOtherPage), Addr);
4159                           /* Read data */
4160                           Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
4161                           data = readw(Addr); /* *((USHORT *)(Addr)); */
4162                           if(data == PhysicalAdrHigh) Done = 1;
4163                        }  /* if */
4164                  }  /* for k */
4165               }  /* if */
4166            }  /* for j */
4167         }  /* for i */
4168 }
4169
4170 static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
4171 {
4172         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4173         u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4174         u16 index, rindex, memtype = 0;
4175
4176         outSISIDXREG(SISSR,0x05,0x86);
4177
4178         if(ivideo->sishw_ext.UseROM) {
4179            if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
4180               memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4181            } else {
4182               inSISIDXREG(SISSR,0x3a,memtype);
4183            }
4184            memtype &= 0x07;
4185         }
4186
4187         if(ivideo->revision_id <= 0x13) {
4188            v1 = 0x44; v2 = 0x42; v3 = 0x80;
4189            v4 = 0x44; v5 = 0x42; v6 = 0x80;
4190         } else {
4191            v1 = 0x68; v2 = 0x43; v3 = 0x80;  /* Assume 125Mhz MCLK */
4192            v4 = 0x68; v5 = 0x43; v6 = 0x80;  /* Assume 125Mhz ECLK */
4193            if(ivideo->sishw_ext.UseROM) {
4194               index = memtype * 5;
4195               rindex = index + 0x54;
4196               v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4197               v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4198               v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4199               rindex = index + 0x7c;
4200               v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4201               v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4202               v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4203            }
4204         }
4205         outSISIDXREG(SISSR,0x28,v1);
4206         outSISIDXREG(SISSR,0x29,v2);
4207         outSISIDXREG(SISSR,0x2a,v3);
4208         outSISIDXREG(SISSR,0x2e,v4);
4209         outSISIDXREG(SISSR,0x2f,v5);
4210         outSISIDXREG(SISSR,0x30,v6);
4211         v1 = 0x10;
4212         if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
4213         outSISIDXREG(SISSR,0x07,v1);       /* DAC speed */
4214         outSISIDXREG(SISSR,0x11,0x0f);     /* DDC, power save */
4215         v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4216         v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4217         if(ivideo->sishw_ext.UseROM) {
4218            memtype += 0xa5;
4219            v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
4220            v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
4221            v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
4222            v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
4223            v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
4224            v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
4225            v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
4226            v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
4227         }
4228         if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
4229         outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4230         outSISIDXREG(SISSR,0x16,v2);
4231         outSISIDXREG(SISSR,0x17,v3);
4232         outSISIDXREG(SISSR,0x18,v4);
4233         outSISIDXREG(SISSR,0x19,v5);
4234         outSISIDXREG(SISSR,0x1a,v6);
4235         outSISIDXREG(SISSR,0x1b,v7);
4236         outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
4237         andSISIDXREG(SISSR,0x15,0xfb);
4238         orSISIDXREG(SISSR,0x15,0x04);
4239         if(ivideo->sishw_ext.UseROM) {
4240            if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
4241               orSISIDXREG(SISSR,0x19,0x20);
4242            }
4243         }
4244         v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
4245         if(ivideo->revision_id >= 0x80) v1 |= 0x01;
4246         outSISIDXREG(SISSR,0x1f,v1);
4247         outSISIDXREG(SISSR,0x20,0xa0);     /* linear & relocated io */
4248         v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4249         if(ivideo->sishw_ext.UseROM) {
4250            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
4251            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
4252            v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
4253         }
4254         outSISIDXREG(SISSR,0x23,v1);
4255         outSISIDXREG(SISSR,0x24,v2);
4256         outSISIDXREG(SISSR,0x25,v3);
4257         outSISIDXREG(SISSR,0x21,0x84);
4258         outSISIDXREG(SISSR,0x22,0x00);
4259         outSISIDXREG(SISCR,0x37,0x00);
4260         orSISIDXREG(SISPART1,0x24,0x01);   /* unlock crt2 */
4261         outSISIDXREG(SISPART1,0x00,0x00);
4262         v1 = 0x40; v2 = 0x11;
4263         if(ivideo->sishw_ext.UseROM) {
4264            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
4265            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
4266         }
4267         outSISIDXREG(SISPART1,0x02,v1);
4268         if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
4269         inSISIDXREG(SISPART4,0x00,reg);
4270         if((reg == 1) || (reg == 2)) {
4271            outSISIDXREG(SISCR,0x37,0x02);
4272            outSISIDXREG(SISPART2,0x00,0x1c);
4273            v4 = 0x00; v5 = 0x00; v6 = 0x10;
4274            if(ivideo->sishw_ext.UseROM) {
4275               v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
4276               v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
4277               v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
4278            }
4279            outSISIDXREG(SISPART4,0x0d,v4);
4280            outSISIDXREG(SISPART4,0x0e,v5);
4281            outSISIDXREG(SISPART4,0x10,v6);
4282            outSISIDXREG(SISPART4,0x0f,0x3f);
4283            inSISIDXREG(SISPART4,0x01,reg);
4284            if(reg >= 0xb0) {
4285               inSISIDXREG(SISPART4,0x23,reg);
4286               reg &= 0x20;
4287               reg <<= 1;
4288               outSISIDXREG(SISPART4,0x23,reg);
4289            }
4290         } else {
4291            v2 &= ~0x10;
4292         }
4293         outSISIDXREG(SISSR,0x32,v2);
4294         andSISIDXREG(SISPART1,0x24,0xfe);  /* Lock CRT2 */
4295         inSISIDXREG(SISSR,0x16,reg);
4296         reg &= 0xc3;
4297         outSISIDXREG(SISCR,0x35,reg);
4298         outSISIDXREG(SISCR,0x83,0x00);
4299 #if !defined(__i386__) && !defined(__x86_64__)
4300         if(sisfb_videoram) {
4301            outSISIDXREG(SISSR,0x13,0x28);  /* ? */
4302            reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4303            outSISIDXREG(SISSR,0x14,reg);
4304         } else {
4305 #endif
4306            /* Need to map max FB size for finding out about RAM size */
4307            ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
4308            if(ivideo->sishw_ext.pjVideoMemoryAddress) {
4309               sisfb_setramsize300(pdev);
4310               iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
4311            } else {
4312               printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4313               outSISIDXREG(SISSR,0x13,0x28);  /* ? */
4314               outSISIDXREG(SISSR,0x14,0x47);  /* 8MB, 64bit default */
4315            }
4316 #if !defined(__i386__) && !defined(__x86_64__)
4317         }
4318 #endif
4319         if(ivideo->sishw_ext.UseROM) {
4320            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
4321            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
4322         } else {
4323            inSISIDXREG(SISSR,0x3a,reg);
4324            if((reg & 0x30) == 0x30) {
4325               v1 = 0x04; /* PCI */
4326               v2 = 0x92;
4327            } else {
4328               v1 = 0x14; /* AGP */
4329               v2 = 0xb2;
4330            }
4331         }
4332         outSISIDXREG(SISSR,0x21,v1);
4333         outSISIDXREG(SISSR,0x22,v2);
4334 }
4335 #endif
4336
4337 #ifdef CONFIG_FB_SIS_315
4338 static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
4339 {
4340 #ifdef YET_TO_BE_DONE
4341         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4342         u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4343         u16 index, rindex, memtype = 0;
4344         u32 reg1_32, reg2_32, reg3_32;
4345         int i;
4346
4347         /* Unlock */
4348         /* outSISIDXREG(0x3c4,0x05,0x86); */
4349         outSISIDXREG(SISSR,0x05,0x86);
4350
4351         /* Enable relocated i/o ports */
4352         /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
4353         setSISIDXREG(SISSR,0x20,~0x10,0x20);
4354
4355         /* Clear regs */
4356         for(i = 0; i < 0x22; i++) {
4357            outSISIDXREG(SISSR,(0x06 + i),0x00);
4358         }
4359         v1 = 0x0d;
4360         if( is 330) v1 = 0x0b;
4361         for(i = 0; i < v1; i++) {
4362            outSISIDXREG(SISSR,(0x31 + i),0x00);
4363         }
4364         for(i = 0; i < 0x10; i++) {
4365            outSISIDXREG(SISCR,(0x30 + i),0x00);
4366         }
4367
4368         /* Reset clocks */
4369         reg = inSISREG(SISMISCR);
4370         outSISIDXREG(SISSR,0x28,0x81);
4371         outSISIDXREG(SISSR,0x2A,0x00);
4372         outSISIDXREG(SISSR,0x29,0xE1);
4373         outSISREG(SISMISCW,(reg | 0x0c));
4374         outSISIDXREG(SISSR,0x2B,0x81);
4375         outSISIDXREG(SISSR,0x2D,0x00);
4376         outSISIDXREG(SISSR,0x2C,0xE1);
4377         outSISIDXREG(SISSR,0x2E,0x81);
4378         outSISIDXREG(SISSR,0x30,0x00);
4379         outSISIDXREG(SISSR,0x2F,0xE1);
4380         SiS_DDC2Delay(....);
4381         outSISREG(SISMISCW,reg);
4382
4383         /* Get memory type */
4384         if(ivideo->sishw_ext.UseROM) {
4385            if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
4386               memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
4387            } else {
4388               inSISIDXREG(SISSR,0x3a,memtype);
4389            }
4390            memtype &= 0x03;
4391            if( is 330 ) {
4392               if(memtype <= 1) memtype = 0;
4393               else {
4394                  inSISIDXREG(SISCR,0x5F,reg);
4395                  reg &= 0x30;
4396                  switch(reg) {
4397                  case 0x00: memtype = 1; break;
4398                  case 0x10: memtype = 3; break;
4399                  case 0x20: memtype = 3; break;
4400                  default:   memtype = 2;
4401                  }
4402               }
4403            }
4404         }
4405
4406         /* Set clocks */
4407         v1 = 0x3b; v2 = 0x22; v3 = 0x01;  /* Assume 143Mhz MCLK */
4408         v4 = 0x5c; v5 = 0x23; v6 = 0x01;  /* Assume 166Mhz ECLK */
4409         if(ivideo->sishw_ext.UseROM) {
4410            index = memtype * 5;
4411            rindex = index + 0x54;
4412            v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4413            v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4414            v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4415            rindex = index + 0x68;
4416            v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4417            v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4418            v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
4419         }
4420         outSISIDXREG(SISSR,0x28,v1);
4421         outSISIDXREG(SISSR,0x29,v2);
4422         outSISIDXREG(SISSR,0x2a,v3);
4423         if( is 330 ) {
4424            inSISIDXREG(SISSR,0x3a,reg);
4425            reg &= 0x03;
4426            if(reg >= 2) {
4427               ...
4428            }
4429         }
4430         outSISIDXREG(SISSR,0x2e,v4);
4431         outSISIDXREG(SISSR,0x2f,v5);
4432         outSISIDXREG(SISSR,0x30,v6);
4433
4434         /* End of comp with 330 */
4435
4436         v1 = 0x18;
4437         if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
4438         outSISIDXREG(SISSR,0x07,v1);
4439         outSISIDXREG(SISSR,0x11,0x0f);
4440
4441         v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
4442         v5 = 0xa0; v6 = 0x00; v7 = 0x30;
4443         if(ivideo->sishw_ext.UseROM) {
4444            index = memtype + 0x7d;
4445            v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4446            v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4447            v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4448            v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4449            v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4450            v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4451            v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4452         }
4453         outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0x7d step 4) */
4454         outSISIDXREG(SISSR,0x16,v2);
4455         outSISIDXREG(SISSR,0x17,v3);
4456         outSISIDXREG(SISSR,0x18,v4);
4457         outSISIDXREG(SISSR,0x19,v5);
4458         outSISIDXREG(SISSR,0x1a,v6);
4459         outSISIDXREG(SISSR,0x1b,v7);
4460         outSISIDXREG(SISSR,0x1c,v8);       /* ---- */
4461
4462         v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
4463         if(ivideo->sishw_ext.UseROM) {
4464            index = memtype + 0xa2;
4465            v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4466            v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4467            v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4468            v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4469            v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4470         }
4471         outSISIDXREG(SISCR,0x40,v1);
4472         outSISIDXREG(SISCR,0x41,v2);
4473         outSISIDXREG(SISCR,0x42,v3);
4474         outSISIDXREG(SISCR,0x43,v4);
4475         outSISIDXREG(SISCR,0x44,v5);
4476
4477         if( is 330 ) {
4478
4479            v1 = 0x;
4480            if(ivideo->sishw_ext.UseROM) {
4481               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4482            }
4483            outSISIDXREG(SISCR,0x59,v1);
4484
4485            v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
4486            v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
4487            if(ivideo->sishw_ext.UseROM) {
4488               index = memtype + 0xbe;
4489               v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
4490               v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
4491               v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
4492               v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
4493               v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
4494               v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
4495               v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
4496               v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
4497            }
4498            outSISIDXREG(SISCR,0x68,v1);
4499            outSISIDXREG(SISCR,0x69,v2);
4500            outSISIDXREG(SISCR,0x6a,v3);
4501            outSISIDXREG(SISCR,0x6b,v4);
4502            outSISIDXREG(SISCR,0x6c,v5);
4503            outSISIDXREG(SISCR,0x6d,v6);
4504            outSISIDXREG(SISCR,0x6e,v7);
4505            outSISIDXREG(SISCR,0x6f,v8);
4506
4507            v1 = 0x20;
4508            inSISIDXREG(SISSR,0x3b,reg);
4509
4510            if(!(reg & 0x04)) {
4511               inSISIDXREG(SISCR,0x5F,reg);
4512               reg &= 0x30;
4513               if(reg) v1 = 0x23;
4514            }
4515            outSISIDXREG(SISCR,0x48,v1);
4516            outSISIDXREG(SISCR,0x4c,0x20);
4517
4518            xx= xxx();
4519            if(xx >= 1) {
4520               v1 = 0x;
4521               if(ivideo->sishw_ext.UseROM) {
4522                  v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
4523               }
4524               outSISIDXREG(SISCR,0x59,v1);
4525            }
4526
4527
4528
4529         } else {
4530
4531            outSISIDXREG(SISCR,0x48,0x23);
4532
4533            andSISIDXREG(SISSR,0x16,0x0f);
4534            if(memtype <= 1) {
4535               orSISIDXREG(SISSR,0x16,0x80);
4536            } else {
4537               v1 = 0x0f;
4538               if(ivideo->sishw_ext.UseROM) {
4539                  v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
4540               }
4541               if(!(v1 & 0x10)) v2 = 0xc0;
4542               else             v2 = 0xd0;
4543               orSISIDXREG(SISSR,0x16,v2);
4544               andSISIDXREG(SISSR,0x16,0x0f);
4545               if(!(v1 & 0x10)) v2 = 0x80;
4546               else             v2 = 0xA0;
4547               orSISIDXREG(SISSR,0x16,v2);
4548            }
4549
4550            if(memtype >= 2) {
4551               const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
4552               const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
4553               for(i = 0; i < 11; i++) {
4554                  outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
4555               }
4556               outSISIDXREG(SISSR,0x3d,0x00);
4557               outSISIDXREG(SISSR,0x3d,0x04);
4558               SiS_DDC2Delay(0x200);
4559               v1 = inSISIDXREG(SISCR,0xEC);
4560               v2 = inSISIDXREG(SISCR,0xED);
4561               reg1_32 = (v2 << 8) | v1;
4562               outSISIDXREG(SISSR,0x3D,0x00);
4563               for(i = 0; i < 11; i++) {
4564                  outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
4565               }
4566               outSISIDXREG(SISSR,0x3d,0x00);
4567               outSISIDXREG(SISSR,0x3d,0x04);
4568               SiS_DDC2Delay(0x200);
4569               v1 = inSISIDXREG(SISCR,0xEC);
4570               v2 = inSISIDXREG(SISCR,0xED);
4571               reg2_32 = (v2 << 8) | v1;
4572               outSISIDXREG(SISSR,0x3D,0x00);
4573               reg3_32 = reg2_32 << 1;
4574               reg2_32 >>= 1;
4575               reg3_32 += reg2_32;
4576               v1 = 0x40;
4577               if(reg3_32 > reg1_32) v1 = 0x10;
4578                  outSISIDXREG(SISCR,0x59,v1);
4579            }
4580
4581         }
4582
4583         v1 = 0x00;
4584         if(ivideo->sishw_ext.UseROM) {
4585            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
4586         }
4587         outSISIDXREG(SISSR,0x1f,v1);
4588
4589         outSISIDXREG(SISSR,0x20,0x20);
4590
4591         v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
4592         if(ivideo->sishw_ext.UseROM) {
4593            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
4594            v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
4595            v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
4596         }
4597         outSISIDXREG(SISSR,0x23,v1);
4598         outSISIDXREG(SISSR,0x24,v2);
4599         outSISIDXREG(SISSR,0x25,v3);
4600
4601         outSISIDXREG(SISSR,0x21,0x84);
4602         outSISIDXREG(SISSR,0x22,0x00);
4603         outSISIDXREG(SISSR,0x27,0x1f);
4604
4605         v1 = 0x00; v2 = 0x00;
4606         if(ivideo->sishw_ext.UseROM) {
4607            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
4608            v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
4609         }
4610         outSISIDXREG(SISSR,0x31,v1);
4611         outSISIDXREG(SISSR,0x33,v2);
4612
4613         v1 = 0x11;
4614         if(ivideo->sishw_ext.UseROM) {
4615            v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
4616         }
4617         v2 = inSISIDXREG(SISPART4,0x00);
4618         if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
4619         outSISIDXREG(SISSR,0x32,v1);
4620
4621         /* AGP */
4622         pci_read_config_long(pdev, 0x50, &reg1_32);
4623         reg1_32 >>= 20;
4624         reg1_32 &= 0x0f;
4625         if(reg1_32 == 1) {
4626            v1 = 0xAA; v2 = 0x33;
4627            if(ivideo->sishw_ext.UseROM) {
4628               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
4629               v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
4630            }
4631         } else {
4632            v1 = 0x88; v2 = 0x03;
4633            if(ivideo->sishw_ext.UseROM) {
4634               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
4635               v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
4636            }
4637         }
4638         outSISIDXREG(SISCR,0x49,v1);
4639         outSISIDXREG(SISSR,0x25,v2);
4640
4641         v1 = inSISIDXREG(SISPART4,0x00);
4642         if((v1 == 1) || (v1 == 2)) {
4643            orSISIDXREG(SISPART1,0x2F,0x01);  /* Unlock CRT2 */
4644            outSISIDXREG(SISPART1,0x00,0x00);
4645            v1 = 0x00;
4646            if(ivideo->sishw_ext.UseROM) {
4647               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
4648            }
4649            outSISIDXREG(SISPART1,0x02,v1);
4650            outSISIDXREG(SISPART1,0x2E,0x08);
4651            outSISIDXREG(SISPART2,0x00,0x1c);
4652            v1 = 0x40; v2 = 0x00; v3 = 0x80;
4653            if(ivideo->sishw_ext.UseROM) {
4654               v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
4655               v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
4656               v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
4657            }
4658            outSISIDXREG(SISPART4,0x0d,v1);
4659            outSISIDXREG(SISPART4,0x0e,v2);
4660            outSISIDXREG(SISPART4,0x10,v3);
4661            outSISIDXREG(SISPART4,0x0F,0x3F);
4662
4663            inSISIDXREG(SISPART4,0x01,reg);
4664            if(reg >= 0xb0) {
4665               inSISIDXREG(SISPART4,0x23,reg);
4666               reg &= 0x20;
4667               reg <<= 1;
4668               outSISIDXREG(SISPART4,0x23,reg);
4669            }
4670         }
4671         outSISIDXREG(SISCR,0x37,0x02); /* Why? */
4672
4673         outSISIDXREG(SISCR,0x83,0x00);
4674         outSISIDXREG(SISCR,0x90,0x00);
4675         andSISIDXREG(SISSR,0x5B,0xDF);
4676         outSISIDXREG(SISVID,0x00,0x86);
4677         outSISIDXREG(SISVID,0x32,0x00);
4678         outSISIDXREG(SISVID,0x30,0x00);
4679         outSISIDXREG(SISVID,0x32,0x01);
4680         outSISIDXREG(SISVID,0x30,0x00);
4681         orSISIDXREG(SISCR,0x63,0x80);
4682         /* End of Init1 */
4683
4684         /* Set Mode 0x2e */
4685
4686         /* Ramsize */
4687         orSISIDXREG(SISSR,0x16,0x0f);
4688         orSISIDXREG(SISSR,0x18,0xA9);
4689         orSISIDXREG(SISSR,0x19,0xA0);
4690         orSISIDXREG(SISSR,0x1B,0x30);
4691         andSISIDXREG(SISSR,0x17,0xF8);
4692         orSISIDXREG(SISSR,0x19,0x03);
4693         andSIDIDXREG(SISSR,0x13,0x00);
4694
4695         /* Need to map max FB size for finding out about RAM size */
4696         ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
4697         if(ivideo->sishw_ext.pjVideoMemoryAddress) {
4698            /* Find out about bus width */
4699            if(memtype <= 1) {
4700               outSISIDXREG(SISSR,0x14,0x02);
4701               andSISIDXREG(SISSR,0x16,0x0F);
4702               orSISIDXREG(SISSR,0x16,0x80);
4703
4704               ...
4705
4706            } else {
4707
4708               ...
4709
4710            }
4711
4712            /* Find out about size */
4713
4714
4715            iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
4716         } else {
4717            printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4718            outSISIDXREG(SISSR,0x14,0x??);  /* 8MB, 64bit default */
4719         }
4720
4721         /* AGP (Missing: Checks for VIA and AMD hosts) */
4722         v1 = 0xA5; v2 = 0xFB;
4723         if(ivideo->sishw_ext.UseROM) {
4724            v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
4725            v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
4726         }
4727         outSISIDXREG(SISSR,0x21,v1);
4728         outSISIDXREG(SISSR,0x22,v2);
4729
4730 #endif
4731         return;
4732 }
4733 #endif
4734
4735
4736 int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4737 {
4738         struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
4739         struct sis_video_info   *ivideo = NULL;
4740         struct fb_info          *sis_fb_info = NULL;
4741         u16 reg16;
4742         u8  reg;
4743         int sisvga_enabled = 0, i;
4744
4745         if(sisfb_off) return -ENXIO;
4746
4747 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
4748         sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
4749         if(!sis_fb_info) return -ENOMEM;
4750 #else
4751         sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
4752         if(!sis_fb_info) return -ENOMEM;
4753         memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
4754         sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
4755 #endif
4756
4757         ivideo = (struct sis_video_info *)sis_fb_info->par;
4758         ivideo->memyselfandi = sis_fb_info;
4759
4760         if(card_list == NULL) {
4761            ivideo->cardnumber = 0;
4762         } else {
4763            struct sis_video_info *countvideo = card_list;
4764            ivideo->cardnumber = 1;
4765            while ((countvideo = countvideo->next) != NULL) ivideo->cardnumber++;
4766         }
4767
4768         strncpy(ivideo->myid, chipinfo->chip_name, 30);
4769
4770         ivideo->chip_id = pdev->device;
4771         pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
4772         ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
4773         pci_read_config_word(pdev, PCI_COMMAND, &reg16);
4774         sisvga_enabled = reg16 & 0x01;
4775         ivideo->pcibus = pdev->bus->number;
4776         ivideo->pcislot = PCI_SLOT(pdev->devfn);
4777         ivideo->pcifunc = PCI_FUNC(pdev->devfn);
4778         ivideo->subsysvendor = pdev->subsystem_vendor;
4779         ivideo->subsysdevice = pdev->subsystem_device;
4780 #ifdef SIS_CONFIG_COMPAT
4781         ivideo->ioctl32registered = 0;
4782         ivideo->ioctl32vblankregistered = 0;
4783 #endif
4784
4785 #ifndef MODULE
4786         if(sisfb_mode_idx == -1) {
4787                 sisfb_get_vga_mode_from_kernel();
4788         }
4789 #endif
4790
4791         ivideo->chip = chipinfo->chip;
4792         ivideo->sisvga_engine = chipinfo->vgaengine;
4793         ivideo->hwcursor_size = chipinfo->hwcursor_size;
4794         ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
4795         ivideo->mni = chipinfo->mni;
4796
4797         ivideo->detectedpdc  = 0xff;
4798         ivideo->detectedpdca = 0xff;
4799         ivideo->detectedlcda = 0xff;
4800
4801         ivideo->sisfb_thismonitor.datavalid = FALSE;
4802
4803         ivideo->sisfb_parm_mem = sisfb_parm_mem;
4804         ivideo->sisfb_accel = sisfb_accel;
4805         ivideo->sisfb_ypan = sisfb_ypan;
4806         ivideo->sisfb_max = sisfb_max;
4807         ivideo->sisfb_userom = sisfb_userom;
4808         ivideo->sisfb_useoem = sisfb_useoem;
4809         ivideo->sisfb_mode_idx = sisfb_mode_idx;
4810         ivideo->sisfb_parm_rate = sisfb_parm_rate;
4811         ivideo->sisfb_crt1off = sisfb_crt1off;
4812         ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
4813         ivideo->sisfb_crt2type = sisfb_crt2type;
4814         ivideo->sisfb_crt2flags = sisfb_crt2flags;
4815         /* pdc(a), scalelcd, special timing, lvdshl handled below */
4816         ivideo->sisfb_dstn = sisfb_dstn;
4817         ivideo->sisfb_fstn = sisfb_fstn;
4818         ivideo->sisfb_tvplug = sisfb_tvplug;
4819         ivideo->sisfb_tvstd = sisfb_tvstd;
4820         ivideo->tvxpos = sisfb_tvxposoffset;
4821         ivideo->tvypos = sisfb_tvyposoffset;
4822         ivideo->sisfb_filter = sisfb_filter;
4823         ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
4824 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
4825         ivideo->sisfb_inverse = sisfb_inverse;
4826 #endif
4827
4828         ivideo->refresh_rate = 0;
4829         if(ivideo->sisfb_parm_rate != -1) {
4830            ivideo->refresh_rate = ivideo->sisfb_parm_rate;
4831         }
4832
4833         ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
4834         ivideo->SiS_Pr.CenterScreen = -1;
4835         ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
4836         ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
4837
4838         ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
4839         ivideo->SiS_Pr.SiS_CHOverScan = -1;
4840         ivideo->SiS_Pr.SiS_ChSW = FALSE;
4841         ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
4842         ivideo->SiS_Pr.HaveEMI = FALSE;
4843         ivideo->SiS_Pr.HaveEMILCD = FALSE;
4844         ivideo->SiS_Pr.OverruleEMI = FALSE;
4845         ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
4846         ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
4847         ivideo->SiS_Pr.PDC  = -1;
4848         ivideo->SiS_Pr.PDCA = -1;
4849 #ifdef CONFIG_FB_SIS_315
4850         if(ivideo->chip >= SIS_330) {
4851            ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
4852            if(ivideo->chip >= SIS_661) {
4853               ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
4854            }
4855         }
4856 #endif
4857
4858         memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
4859
4860         pci_set_drvdata(pdev, ivideo);
4861
4862         /* Patch special cases */
4863         if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
4864                 switch(ivideo->nbridge->device) {
4865 #ifdef CONFIG_FB_SIS_300
4866                 case PCI_DEVICE_ID_SI_730:
4867                         ivideo->chip = SIS_730;
4868                         strcpy(ivideo->myid, "SiS 730");
4869                         break;
4870 #endif
4871 #ifdef CONFIG_FB_SIS_315
4872                 case PCI_DEVICE_ID_SI_651:
4873                         /* ivideo->chip is ok */
4874                         strcpy(ivideo->myid, "SiS 651");
4875                         break;
4876                 case PCI_DEVICE_ID_SI_740:
4877                         ivideo->chip = SIS_740;
4878                         strcpy(ivideo->myid, "SiS 740");
4879                         break;
4880                 case PCI_DEVICE_ID_SI_661:
4881                         ivideo->chip = SIS_661;
4882                         strcpy(ivideo->myid, "SiS 661");
4883                         break;
4884                 case PCI_DEVICE_ID_SI_741:
4885                         ivideo->chip = SIS_741;
4886                         strcpy(ivideo->myid, "SiS 741");
4887                         break;
4888                 case PCI_DEVICE_ID_SI_760:
4889                         ivideo->chip = SIS_760;
4890                         strcpy(ivideo->myid, "SiS 760");
4891                         break;
4892 #endif
4893                 }
4894         }
4895
4896 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4897         strcpy(sis_fb_info->modename, ivideo->myid);
4898 #endif
4899
4900         ivideo->sishw_ext.jChipType = ivideo->chip;
4901
4902 #ifdef CONFIG_FB_SIS_315
4903         if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
4904            (ivideo->sishw_ext.jChipType == SIS_315)) {
4905                 ivideo->sishw_ext.jChipType = SIS_315H;
4906         }
4907 #endif
4908
4909         ivideo->video_base = pci_resource_start(pdev, 0);
4910         ivideo->mmio_base  = pci_resource_start(pdev, 1);
4911         ivideo->mmio_size  = pci_resource_len(pdev, 1);
4912         ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
4913         ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
4914
4915         if(!sisvga_enabled) {
4916                 if(pci_enable_device(pdev)) {
4917                         pci_set_drvdata(pdev, NULL);
4918                         kfree(sis_fb_info);
4919                         return -EIO;
4920                 }
4921         }
4922
4923         SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
4924
4925 #ifdef CONFIG_FB_SIS_300
4926         /* Find PCI systems for Chrontel/GPIO communication setup */
4927         if(ivideo->chip == SIS_630) {
4928            i=0;
4929            do {
4930               if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
4931                  mychswtable[i].subsysCard   == ivideo->subsysdevice) {
4932                  ivideo->SiS_Pr.SiS_ChSW = TRUE;
4933                  printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
4934                         mychswtable[i].vendorName, mychswtable[i].cardName);
4935                  break;
4936               }
4937               i++;
4938            } while(mychswtable[i].subsysVendor != 0);
4939         }
4940 #endif
4941
4942         outSISIDXREG(SISSR, 0x05, 0x86);
4943
4944         if( (!sisvga_enabled)
4945 #if !defined(__i386__) && !defined(__x86_64__)
4946                               || (sisfb_resetcard)
4947 #endif
4948                                                    ) {
4949                 for(i = 0x30; i <= 0x3f; i++) {
4950                         outSISIDXREG(SISCR,i,0x00);
4951                 }
4952         }
4953
4954         /* Find out about current video mode */
4955         inSISIDXREG(SISCR,0x34,reg);
4956         if(reg & 0x7f) {
4957                 ivideo->modeprechange = reg & 0x7f;
4958         } else {
4959                 ivideo->modeprechange = 0x03;
4960 #if defined(__i386__) || defined(__x86_64__)
4961                 {
4962                         unsigned char __iomem *tt = ioremap(0, 0x1000);
4963                         if(tt) {
4964                                 ivideo->modeprechange = tt[0x449];
4965                                 iounmap(tt);
4966                         }
4967                 }
4968 #endif
4969         }
4970
4971 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4972 #ifdef MODULE
4973         if((reg & 0x80) && (reg != 0xff)) {
4974            if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
4975               printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
4976               pci_set_drvdata(pdev, NULL);
4977               kfree(sis_fb_info);
4978               return -EBUSY;
4979            }
4980         }
4981 #endif  
4982 #endif
4983
4984         ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
4985 #ifdef CONFIG_FB_SIS_300
4986         if(ivideo->sisvga_engine == SIS_300_VGA) {
4987            if(ivideo->chip != SIS_300) {
4988               inSISIDXREG(SISSR, 0x1a, reg);
4989               if(!(reg & 0x10)) {
4990                  ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
4991               }
4992            }
4993         }
4994 #endif
4995
4996         ivideo->bios_abase = NULL;
4997         ivideo->bios_vbase = NULL;
4998         if(ivideo->sisfb_userom) {
4999             ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
5000 #if defined(__i386__) || defined(__x86_64__)
5001             ivideo->bios_vbase = ivideo->sishw_ext.pjVirtualRomBase;    /* mapped */
5002 #else
5003             ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;    /* allocated */
5004 #endif
5005             if(ivideo->sishw_ext.pjVirtualRomBase) {
5006                 printk(KERN_INFO "sisfb: Video ROM found and %s to 0x%p\n",
5007                         ivideo->bios_vbase ? "mapped" : "copied",
5008                         ivideo->sishw_ext.pjVirtualRomBase);
5009                 ivideo->sishw_ext.UseROM = TRUE;
5010             } else {
5011                 ivideo->sishw_ext.UseROM = FALSE;
5012                 printk(KERN_INFO "sisfb: Video ROM not found\n");
5013             }
5014         } else {
5015             ivideo->sishw_ext.pjVirtualRomBase = NULL;
5016             ivideo->sishw_ext.UseROM = FALSE;
5017             printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5018         }
5019
5020         /* Find systems for special custom timing */
5021         if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5022            int j;
5023            unsigned char *biosver = NULL;
5024            unsigned char *biosdate = NULL;
5025            BOOLEAN footprint;
5026            u32 chksum = 0;
5027
5028            if(ivideo->sishw_ext.UseROM) {
5029               biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5030               biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5031               for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5032            }
5033
5034            i=0;
5035            do {
5036               if( (mycustomttable[i].chipID == ivideo->chip) &&
5037                   ((!strlen(mycustomttable[i].biosversion)) ||
5038                    (ivideo->sishw_ext.UseROM &&
5039                    (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5040                   ((!strlen(mycustomttable[i].biosdate)) ||
5041                    (ivideo->sishw_ext.UseROM &&
5042                    (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5043                   ((!mycustomttable[i].bioschksum) ||
5044                    (ivideo->sishw_ext.UseROM &&
5045                    (mycustomttable[i].bioschksum == chksum)))   &&
5046                   (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5047                   (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5048                  footprint = TRUE;
5049                  for(j = 0; j < 5; j++) {
5050                     if(mycustomttable[i].biosFootprintAddr[j]) {
5051                        if(ivideo->sishw_ext.UseROM) {
5052                           if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5053                                 mycustomttable[i].biosFootprintData[j]) {
5054                              footprint = FALSE;
5055                           }
5056                        } else footprint = FALSE;
5057                     }
5058                  }
5059                  if(footprint) {
5060                     ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5061                     printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5062                         mycustomttable[i].vendorName,
5063                         mycustomttable[i].cardName);
5064                     printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5065                         mycustomttable[i].optionName);
5066                     break;
5067                  }
5068               }
5069               i++;
5070            } while(mycustomttable[i].chipID);
5071         }
5072
5073 #ifdef CONFIG_FB_SIS_300
5074         if(ivideo->sisvga_engine == SIS_300_VGA) {
5075                 if( (!sisvga_enabled)
5076 #if !defined(__i386__) && !defined(__x86_64__)
5077                                       || (sisfb_resetcard)
5078 #endif
5079                                                            ) {
5080                         if(ivideo->chip == SIS_300) {
5081                                 sisfb_post_sis300(pdev);
5082                         }
5083                 }
5084         }
5085 #endif
5086
5087 #ifdef CONFIG_FB_SIS_315
5088         if(ivideo->sisvga_engine == SIS_315_VGA) {
5089                 if( (!sisvga_enabled)
5090 #if !defined(__i386__) && !defined(__x86_64__)
5091                                      || (sisfb_resetcard)
5092 #endif
5093                                                           ) {
5094                         if((ivideo->chip == SIS_315H)   ||
5095                            (ivideo->chip == SIS_315)    ||
5096                            (ivideo->chip == SIS_315PRO) ||
5097                            (ivideo->chip == SIS_330)) {
5098                                 sisfb_post_sis315330(pdev);
5099                         }
5100                 }
5101         }
5102 #endif
5103
5104         if(sisfb_get_dram_size(ivideo)) {
5105                 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5106                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5107                 pci_set_drvdata(pdev, NULL);
5108                 kfree(sis_fb_info);
5109                 return -ENODEV;
5110         }
5111
5112         if((ivideo->sisfb_mode_idx < 0) ||
5113            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5114                 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
5115                 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5116                 /* Enable 2D accelerator engine */
5117                 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5118         }
5119
5120         if(sisfb_pdc != 0xff) {
5121            if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5122            else                                     sisfb_pdc &= 0x1f;
5123            ivideo->SiS_Pr.PDC = sisfb_pdc;
5124         }
5125 #ifdef CONFIG_FB_SIS_315
5126         if(ivideo->sisvga_engine == SIS_315_VGA) {
5127            if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5128         }
5129 #endif
5130
5131         if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5132                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5133                 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5134                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5135                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5136                 pci_set_drvdata(pdev, NULL);
5137                 kfree(sis_fb_info);
5138                 return -ENODEV;
5139         }
5140
5141         if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5142                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5143                 release_mem_region(ivideo->video_base, ivideo->video_size);
5144                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5145                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5146                 pci_set_drvdata(pdev, NULL);
5147                 kfree(sis_fb_info);
5148                 return -ENODEV;
5149         }
5150
5151         ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
5152         ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase;
5153         if(!ivideo->video_vbase) {
5154                 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5155                 release_mem_region(ivideo->video_base, ivideo->video_size);
5156                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5157                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5158                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5159                 pci_set_drvdata(pdev, NULL);
5160                 kfree(sis_fb_info);
5161                 return -ENODEV;
5162         }
5163
5164         ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
5165         if(!ivideo->mmio_vbase) {
5166                 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5167                 iounmap(ivideo->video_vbase);
5168                 release_mem_region(ivideo->video_base, ivideo->video_size);
5169                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5170                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5171                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5172                 pci_set_drvdata(pdev, NULL);
5173                 kfree(sis_fb_info);
5174                 return -ENODEV;
5175         }
5176
5177         printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %ldk\n",
5178                 ivideo->video_base, ivideo->video_vbase, ivideo->video_size / 1024);
5179
5180         printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
5181                 ivideo->mmio_base, ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5182
5183         if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5184                 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5185         }
5186
5187         /* Used for clearing the screen only, therefore respect our mem limit */
5188         ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5189
5190         ivideo->mtrr = 0;
5191
5192         ivideo->vbflags = 0;
5193         ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5194         ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
5195         ivideo->defmodeidx    = DEFAULT_MODE;
5196
5197         ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5198
5199         if((ivideo->sisfb_mode_idx < 0) ||
5200            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5201
5202                 sisfb_sense_crt1(ivideo);
5203
5204                 sisfb_get_VB_type(ivideo);
5205
5206                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5207                         sisfb_detect_VB_connect(ivideo);
5208                 }
5209
5210                 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5211
5212                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5213                    if(ivideo->sisfb_crt2type != -1) {
5214                       if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5215                          ivideo->currentvbflags |= CRT2_LCD;
5216                       } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5217                          ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5218                       }
5219                    } else {
5220                       /* Chrontel 700x TV detection often unreliable, therefore use a
5221                        * different default order on such machines
5222                        */
5223                       if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5224                          if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
5225                          else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
5226                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5227                       } else {
5228                          if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
5229                          else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5230                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5231                       }
5232                    }
5233                 }
5234
5235                 if(ivideo->vbflags & CRT2_LCD) {
5236                    inSISIDXREG(SISCR, 0x36, reg);
5237                    reg &= 0x0f;
5238                    if(ivideo->sisvga_engine == SIS_300_VGA) {
5239                       ivideo->sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
5240                    } else if(ivideo->chip >= SIS_661) {
5241                       ivideo->sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
5242                    } else {
5243                       ivideo->sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
5244                       if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5245                          if((ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_2) &&
5246                             (ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_3)) {
5247                             ivideo->sishw_ext.ulCRT2LCDType = LCD_320x480;
5248                          }
5249                       }
5250                    }
5251                    if(ivideo->sishw_ext.ulCRT2LCDType == LCD_UNKNOWN) {
5252                       ivideo->sishw_ext.ulCRT2LCDType = LCD_1024x768;
5253                       printk(KERN_DEBUG "sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg);
5254                    }
5255                    for(i = 0; i < SIS_LCD_NUMBER; i++) {
5256                       if(ivideo->sishw_ext.ulCRT2LCDType == sis_lcd_data[i].lcdtype) {
5257                          ivideo->lcdxres = sis_lcd_data[i].xres;
5258                          ivideo->lcdyres = sis_lcd_data[i].yres;
5259                          ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5260                          break;
5261                       }
5262                    }
5263                    if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5264                         ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5265                    } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5266                         ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
5267                    }
5268                    printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5269                                 ivideo->lcdxres, ivideo->lcdyres);
5270                 }
5271
5272 #ifdef CONFIG_FB_SIS_300
5273                 /* Save the current PanelDelayCompensation if the LCD is currently used */
5274                 if(ivideo->sisvga_engine == SIS_300_VGA) {
5275                    if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5276                        int tmp;
5277                        inSISIDXREG(SISCR,0x30,tmp);
5278                        if(tmp & 0x20) {
5279                           /* Currently on LCD? If yes, read current pdc */
5280                           inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5281                           ivideo->detectedpdc &= 0x3c;
5282                           if(ivideo->SiS_Pr.PDC == -1) {
5283                              /* Let option override detection */
5284                              ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5285                           }
5286                           printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5287                                  ivideo->detectedpdc);
5288                        }
5289                        if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5290                           printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5291                                  ivideo->SiS_Pr.PDC);
5292                        }
5293                    }
5294                 }
5295 #endif
5296
5297 #ifdef CONFIG_FB_SIS_315
5298                 if(ivideo->sisvga_engine == SIS_315_VGA) {
5299
5300                    /* Try to find about LCDA */
5301                    if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5302                       int tmp;
5303                       inSISIDXREG(SISPART1,0x13,tmp);
5304                       if(tmp & 0x04) {
5305                          ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5306                          ivideo->detectedlcda = 0x03;
5307                       }
5308                    }
5309
5310                    /* Save PDC */
5311                    if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5312                       int tmp;
5313                       inSISIDXREG(SISCR,0x30,tmp);
5314                       if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5315                          /* Currently on LCD? If yes, read current pdc */
5316                          u8 pdc;
5317                          inSISIDXREG(SISPART1,0x2D,pdc);
5318                          ivideo->detectedpdc  = (pdc & 0x0f) << 1;
5319                          ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5320                          inSISIDXREG(SISPART1,0x35,pdc);
5321                          ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5322                          inSISIDXREG(SISPART1,0x20,pdc);
5323                          ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5324                          if(ivideo->newrom) {
5325                             /* New ROM invalidates other PDC resp. */
5326                             if(ivideo->detectedlcda != 0xff) {
5327                                ivideo->detectedpdc = 0xff;
5328                             } else {
5329                                ivideo->detectedpdca = 0xff;
5330                             }
5331                          }
5332                          if(ivideo->SiS_Pr.PDC == -1) {
5333                             if(ivideo->detectedpdc != 0xff) {
5334                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5335                             }
5336                          }
5337                          if(ivideo->SiS_Pr.PDCA == -1) {
5338                             if(ivideo->detectedpdca != 0xff) {
5339                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5340                             }
5341                          }
5342                          if(ivideo->detectedpdc != 0xff) {
5343                             printk(KERN_INFO
5344                                  "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5345                                   ivideo->detectedpdc);
5346                          }
5347                          if(ivideo->detectedpdca != 0xff) {
5348                             printk(KERN_INFO
5349                                  "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5350                                   ivideo->detectedpdca);
5351                          }
5352                       }
5353
5354                       /* Save EMI */
5355                       if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5356                          inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5357                          inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5358                          inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5359                          inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5360                          ivideo->SiS_Pr.HaveEMI = TRUE;
5361                          if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5362                                 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5363                          }
5364                       }
5365                    }
5366
5367                    /* Let user override detected PDCs (all bridges) */
5368                    if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5369                       if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5370                          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5371                                  ivideo->SiS_Pr.PDC);
5372                       }
5373                       if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5374                          printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5375                                  ivideo->SiS_Pr.PDCA);
5376                       }
5377                    }
5378
5379                 }
5380 #endif
5381
5382                 if(!ivideo->sisfb_crt1off) {
5383                         sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5384                 } else {
5385                         if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5386                            (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5387                                 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5388                         }
5389                 }
5390
5391                 if(ivideo->sisfb_mode_idx >= 0) {
5392                         int bu = ivideo->sisfb_mode_idx;
5393                         ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5394                                         ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5395                         if(bu != ivideo->sisfb_mode_idx) {
5396                                 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5397                                         sisbios_mode[bu].xres,
5398                                         sisbios_mode[bu].yres,
5399                                         sisbios_mode[bu].bpp);
5400                         }
5401                 }
5402
5403                 if(ivideo->sisfb_mode_idx < 0) {
5404                         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5405                            case CRT2_LCD:
5406                                 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5407                                 break;
5408                            case CRT2_TV:
5409                                 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5410                                 break;
5411                            default:
5412                                 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5413                                 break;
5414                         }
5415                 }
5416
5417                 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5418
5419                 if(ivideo->refresh_rate != 0) {
5420                         sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5421                 }
5422
5423                 if(ivideo->rate_idx == 0) {
5424                         ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5425                         ivideo->refresh_rate = 60;
5426                 }
5427
5428                 if(ivideo->sisfb_thismonitor.datavalid) {
5429                         if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5430                                               ivideo->rate_idx, ivideo->refresh_rate)) {
5431                                 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5432                         }
5433                 }
5434
5435                 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5436                 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5437                 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5438
5439                 sisfb_set_vparms(ivideo);
5440                 
5441 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  
5442
5443                 /* ---------------- For 2.4: Now switch the mode ------------------ */          
5444                 
5445                 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5446                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5447                         ivideo->refresh_rate);
5448
5449                 sisfb_pre_setmode(ivideo);
5450
5451                 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5452                         printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5453                                                                         ivideo->mode_no);
5454                         iounmap(ivideo->video_vbase);
5455                         iounmap(ivideo->mmio_vbase);
5456                         release_mem_region(ivideo->video_base, ivideo->video_size);
5457                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5458                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5459                         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5460                         pci_set_drvdata(pdev, NULL);
5461                         kfree(sis_fb_info);
5462                         return -EINVAL;
5463                 }
5464
5465                 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5466
5467                 sisfb_post_setmode(ivideo);
5468
5469                 /* Maximize regardless of sisfb_max at startup */
5470                 ivideo->default_var.yres_virtual = 32767;
5471
5472                 /* Force reset of x virtual in crtc_to_var */
5473                 ivideo->default_var.xres_virtual = 0;
5474
5475                 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5476
5477                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5478                 sisfb_set_pitch(ivideo);
5479
5480                 ivideo->accel = 0;
5481                 if(ivideo->sisfb_accel) {
5482                    ivideo->accel = -1;
5483                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5484                 }
5485                 sisfb_initaccel(ivideo);
5486                 
5487                 sis_fb_info->node  = -1;
5488                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5489                 sis_fb_info->fbops = &sisfb_ops;
5490                 sis_fb_info->disp  = &ivideo->sis_disp;
5491                 sis_fb_info->blank = &sisfb_blank;
5492                 sis_fb_info->switch_con = &sisfb_switch;
5493                 sis_fb_info->updatevar  = &sisfb_update_var;
5494                 sis_fb_info->changevar  = NULL;
5495                 strcpy(sis_fb_info->fontname, sisfb_fontname);
5496
5497                 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5498
5499 #else           /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5500
5501                 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5502                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5503                         ivideo->refresh_rate);
5504
5505                 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5506                 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5507                 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5508
5509                 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5510                 
5511                 ivideo->default_var.pixclock = (u32) (1000000000 /
5512                                 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5513                                                 ivideo->mode_no, ivideo->rate_idx));
5514                                                 
5515                 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5516                                 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5517                    if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5518                       ivideo->default_var.pixclock <<= 1;
5519                    }
5520                 }
5521
5522                 if(ivideo->sisfb_ypan) {
5523                    /* Maximize regardless of sisfb_max at startup */
5524                    ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5525                    if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5526                       ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5527                    }
5528                 }
5529
5530                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5531
5532                 ivideo->accel = 0;
5533                 if(ivideo->sisfb_accel) {
5534                    ivideo->accel = -1;
5535 #ifdef STUPID_ACCELF_TEXT_SHIT
5536                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5537 #endif
5538                 }
5539                 sisfb_initaccel(ivideo);
5540
5541 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5542                 sis_fb_info->flags = FBINFO_DEFAULT             |
5543                                      FBINFO_HWACCEL_YPAN        |
5544                                      FBINFO_HWACCEL_XPAN        |
5545                                      FBINFO_HWACCEL_COPYAREA    |
5546                                      FBINFO_HWACCEL_FILLRECT    |
5547                                      ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5548 #else
5549                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5550 #endif
5551                 sis_fb_info->var = ivideo->default_var;
5552                 sis_fb_info->fix = ivideo->sisfb_fix;
5553                 sis_fb_info->screen_base = ivideo->video_vbase;
5554                 sis_fb_info->fbops = &sisfb_ops;
5555
5556                 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5557                 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5558                 
5559                 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5560 #endif          /* 2.6 */
5561
5562                 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5563
5564 #ifdef CONFIG_MTRR
5565                 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5566                                         MTRR_TYPE_WRCOMB, 1);
5567                 if(!ivideo->mtrr) {
5568                         printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5569                 }
5570 #endif
5571
5572 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5573                 vc_resize_con(1, 1, 0);
5574 #endif
5575
5576                 if(register_framebuffer(sis_fb_info) < 0) {
5577                         printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5578                         iounmap(ivideo->video_vbase);
5579                         iounmap(ivideo->mmio_vbase);
5580                         release_mem_region(ivideo->video_base, ivideo->video_size);
5581                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5582                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5583                         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5584                         pci_set_drvdata(pdev, NULL);
5585                         kfree(sis_fb_info);
5586                         return -EINVAL;
5587                 }
5588
5589                 ivideo->registered = 1;
5590
5591                 /* Enlist us */
5592                 ivideo->next = card_list;
5593                 card_list = ivideo;
5594
5595 #ifdef SIS_CONFIG_COMPAT
5596                 {
5597                 int ret;
5598                 /* Our ioctls are all "32/64bit compatible" */
5599                 if(register_ioctl32_conversion(FBIOGET_VBLANK, NULL)) {
5600                    printk(KERN_ERR "sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
5601                 } else {
5602                    ivideo->ioctl32vblankregistered = 1;
5603                 }
5604                 ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
5605                 ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
5606                 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
5607                 ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
5608                 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
5609                 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
5610                 ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
5611                 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
5612                 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
5613                 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
5614                 if(ret) printk(KERN_ERR "sisfb: Error registering ioctl32 translations\n");
5615                 else    ivideo->ioctl32registered = 1;
5616                 }
5617 #endif
5618
5619                 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5620                      ivideo->sisfb_accel ? "enabled" : "disabled",
5621                      ivideo->sisfb_ypan  ?
5622                         (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5623
5624
5625                 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5626 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5627                         GET_FB_IDX(sis_fb_info->node),
5628 #else
5629                         sis_fb_info->node,
5630 #endif
5631                         ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5632
5633                 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5634
5635         }       /* if mode = "none" */
5636
5637         return 0;
5638 }
5639
5640 /*****************************************************/
5641 /*                PCI DEVICE HANDLING                */
5642 /*****************************************************/
5643
5644 static void __devexit sisfb_remove(struct pci_dev *pdev)
5645 {
5646         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5647         struct fb_info        *sis_fb_info = ivideo->memyselfandi;
5648         int                   registered = ivideo->registered;
5649
5650 #ifdef SIS_CONFIG_COMPAT
5651         if(ivideo->ioctl32vblankregistered) {
5652                 if(unregister_ioctl32_conversion(FBIOGET_VBLANK)) {
5653                         printk(KERN_ERR "sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
5654                 }
5655         }
5656         if(ivideo->ioctl32registered) {
5657                 int ret;
5658                 ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
5659                 ret |= unregister_ioctl32_conversion(FBIO_FREE);
5660                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
5661                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
5662                 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
5663                 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
5664                 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
5665                 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
5666                 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
5667                 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
5668                 if(ret) printk(KERN_ERR "sisfb: Error unregistering ioctl32 translations\n");
5669         }
5670 #endif
5671
5672         /* Unmap */
5673         iounmap(ivideo->video_vbase);
5674         iounmap(ivideo->mmio_vbase);
5675         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5676         if(ivideo->bios_abase)    vfree(ivideo->bios_abase);
5677
5678         /* Release mem regions */
5679         release_mem_region(ivideo->video_base, ivideo->video_size);
5680         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5681
5682 #ifdef CONFIG_MTRR
5683         /* Release MTRR region */
5684         if(ivideo->mtrr) {
5685                 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5686         }
5687 #endif
5688
5689         /* Unregister the framebuffer */
5690         if(ivideo->registered) {
5691                 unregister_framebuffer(sis_fb_info);
5692 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5693                 framebuffer_release(sis_fb_info);
5694 #else
5695                 kfree(sis_fb_info);
5696 #endif
5697         }
5698
5699         pci_set_drvdata(pdev, NULL);
5700
5701         /* TODO: Restore the initial mode
5702          * This sounds easy but is as good as impossible
5703          * on many machines with SiS chip and video bridge
5704          * since text modes are always set up differently
5705          * from machine to machine. Depends on the type
5706          * of integration between chipset and bridge.
5707          */
5708         if(registered) {
5709            printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5710         }
5711 };
5712
5713 static struct pci_driver sisfb_driver = {
5714         .name           = "sisfb",
5715         .id_table       = sisfb_pci_table,
5716         .probe          = sisfb_probe,
5717         .remove         = __devexit_p(sisfb_remove)
5718 };
5719
5720 int __init sisfb_init(void)
5721 {
5722 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5723 #ifndef MODULE
5724         char *option = NULL;
5725
5726         if (fb_get_options("sisfb", &option))
5727                 return -ENODEV;
5728         sisfb_setup(option);
5729 #endif
5730 #endif
5731         return(pci_module_init(&sisfb_driver));
5732 }
5733
5734 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
5735 #ifndef MODULE
5736 module_init(sisfb_init);
5737 #endif
5738 #endif
5739
5740 /*****************************************************/
5741 /*                      MODULE                       */
5742 /*****************************************************/
5743
5744 #ifdef MODULE
5745
5746 static char         *mode = NULL;
5747 static int          vesa = -1;
5748 static unsigned int rate = 0;
5749 static unsigned int crt1off = 1;
5750 static unsigned int mem = 0;
5751 static char         *forcecrt2type = NULL;
5752 static int          forcecrt1 = -1;
5753 static int          pdc = -1;
5754 static int          pdc1 = -1;
5755 static int          noaccel = -1;
5756 static int          noypan  = -1;
5757 static int          nomax = -1;
5758 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5759 static int          inverse = 0;
5760 #endif
5761 static int          userom = -1;
5762 static int          useoem = -1;
5763 static char         *tvstandard = NULL;
5764 static int          nocrt2rate = 0;
5765 static int          scalelcd = -1;
5766 static char         *specialtiming = NULL;
5767 static int          lvdshl = -1;
5768 static int          tvxposoffset = 0, tvyposoffset = 0;
5769 static int          filter = -1;
5770 #if !defined(__i386__) && !defined(__x86_64__)
5771 static int          resetcard = 0;
5772 static int          videoram = 0;
5773 #endif
5774
5775 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5776 MODULE_LICENSE("GPL");
5777 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5778
5779 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5780 MODULE_PARM(mem, "i");
5781 MODULE_PARM(noaccel, "i");
5782 MODULE_PARM(noypan, "i");
5783 MODULE_PARM(nomax, "i");
5784 MODULE_PARM(userom, "i");
5785 MODULE_PARM(useoem, "i");
5786 MODULE_PARM(mode, "s");
5787 MODULE_PARM(vesa, "i");
5788 MODULE_PARM(rate, "i");
5789 MODULE_PARM(forcecrt1, "i");
5790 MODULE_PARM(forcecrt2type, "s");
5791 MODULE_PARM(scalelcd, "i");
5792 MODULE_PARM(pdc, "i");
5793 MODULE_PARM(pdc1, "i");
5794 MODULE_PARM(specialtiming, "s");
5795 MODULE_PARM(lvdshl, "i");
5796 MODULE_PARM(tvstandard, "s");
5797 MODULE_PARM(tvxposoffset, "i");
5798 MODULE_PARM(tvyposoffset, "i");
5799 MODULE_PARM(filter, "i");
5800 MODULE_PARM(nocrt2rate, "i");
5801 MODULE_PARM(inverse, "i");
5802 #if !defined(__i386__) && !defined(__x86_64__)
5803 MODULE_PARM(resetcard, "i");
5804 MODULE_PARM(videoram, "i");
5805 #endif
5806 #endif
5807
5808 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5809 module_param(mem, int, 0);
5810 module_param(noaccel, int, 0);
5811 module_param(noypan, int, 0);
5812 module_param(nomax, int, 0);
5813 module_param(userom, int, 0);
5814 module_param(useoem, int, 0);
5815 module_param(mode, charp, 0);
5816 module_param(vesa, int, 0);
5817 module_param(rate, int, 0);
5818 module_param(forcecrt1, int, 0);
5819 module_param(forcecrt2type, charp, 0);
5820 module_param(scalelcd, int, 0);
5821 module_param(pdc, int, 0);
5822 module_param(pdc1, int, 0);
5823 module_param(specialtiming, charp, 0);
5824 module_param(lvdshl, int, 0);
5825 module_param(tvstandard, charp, 0);
5826 module_param(tvxposoffset, int, 0);
5827 module_param(tvyposoffset, int, 0);
5828 module_param(filter, int, 0);
5829 module_param(nocrt2rate, int, 0);
5830 #if !defined(__i386__) && !defined(__x86_64__)
5831 module_param(resetcard, int, 0);
5832 module_param(videoram, int, 0);
5833 #endif
5834 #endif
5835
5836 MODULE_PARM_DESC(mem,
5837         "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5838           "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5839           "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5840           "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5841           "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5842           "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5843           "for XFree86 4.x/X.org 6.7 and later.\n");
5844
5845 MODULE_PARM_DESC(noaccel,
5846         "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5847           "(default: 0)\n");
5848
5849 MODULE_PARM_DESC(noypan,
5850         "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5851           "will be performed by redrawing the screen. (default: 0)\n");
5852
5853 MODULE_PARM_DESC(nomax,
5854         "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5855           "memory for the virtual screen in order to optimize scrolling performance. If\n"
5856           "this is set to anything other than 0, sisfb will not do this and thereby \n"
5857           "enable the user to positively specify a virtual Y size of the screen using\n"
5858           "fbset. (default: 0)\n");
5859
5860 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5861 MODULE_PARM_DESC(mode,
5862         "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5863           "1024x768x16. Other formats supported include XxY-Depth and\n"
5864           "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5865           "number, it will be interpreted as a VESA mode number. (default: none if\n"
5866           "sisfb is a module; this leaves the console untouched and the driver will\n"
5867           "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5868           "is in the kernel)\n");
5869 MODULE_PARM_DESC(vesa,
5870         "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5871           "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5872           "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5873           "0x0103 if sisfb is in the kernel)\n");
5874 #endif
5875
5876 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5877 MODULE_PARM_DESC(mode,
5878        "\nSelects the desired default display mode in the format XxYxDepth,\n"
5879          "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
5880          "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5881          "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
5882
5883 MODULE_PARM_DESC(vesa,
5884        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5885          "0x117 (default: 0x0103)\n");
5886 #endif
5887
5888 MODULE_PARM_DESC(rate,
5889         "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5890           "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5891           "will be ignored (default: 60)\n");
5892
5893 MODULE_PARM_DESC(forcecrt1,
5894         "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5895           "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5896           "0=CRT1 OFF) (default: [autodetected])\n");
5897
5898 MODULE_PARM_DESC(forcecrt2type,
5899         "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5900           "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5901           "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5902           "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5903           "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5904           "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5905           "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5906           "depends on the very hardware in use. (default: [autodetected])\n");
5907
5908 MODULE_PARM_DESC(scalelcd,
5909         "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5910           "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5911           "show black bars around the image, TMDS panels will probably do the scaling\n"
5912           "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5913
5914 MODULE_PARM_DESC(pdc,
5915         "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5916           "should detect this correctly in most cases; however, sometimes this is not\n"
5917           "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5918           "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5919           "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5920           "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5921
5922 #ifdef CONFIG_FB_SIS_315
5923 MODULE_PARM_DESC(pdc1,
5924         "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5925           "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5926           "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5927           "implemented yet.\n");
5928 #endif
5929
5930 MODULE_PARM_DESC(specialtiming,
5931         "\nPlease refer to documentation for more information on this option.\n");
5932
5933 MODULE_PARM_DESC(lvdshl,
5934         "\nPlease refer to documentation for more information on this option.\n");
5935
5936 MODULE_PARM_DESC(tvstandard,
5937         "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5938           "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5939
5940 MODULE_PARM_DESC(tvxposoffset,
5941         "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5942           "Default: 0\n");
5943
5944 MODULE_PARM_DESC(tvyposoffset,
5945         "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5946           "Default: 0\n");
5947
5948 MODULE_PARM_DESC(filter,
5949         "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5950           "(Possible values 0-7, default: [no filter])\n");
5951
5952 MODULE_PARM_DESC(nocrt2rate,
5953         "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5954           "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5955
5956 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5957 MODULE_PARM_DESC(inverse,
5958         "\nSetting this to anything but 0 should invert the display colors, but this\n"
5959           "does not seem to work. (default: 0)\n");
5960 #endif
5961
5962 #if !defined(__i386__) && !defined(__x86_64__)
5963 #ifdef CONFIG_FB_SIS_300
5964 MODULE_PARM_DESC(resetcard,
5965         "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5966           "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5967           "Default: 0\n");
5968
5969 MODULE_PARM_DESC(videoram,
5970         "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5971           "some non-x86 architectures where the memory auto detection fails. Only\n"
5972           "relevant if resetcard is set, too. Default: [auto-detect]\n");
5973 #endif
5974 #endif
5975
5976 int __init sisfb_init_module(void)
5977 {
5978         sisfb_setdefaultparms();
5979
5980         if(rate) sisfb_parm_rate = rate;
5981
5982         if((scalelcd == 0) || (scalelcd == 1)) {
5983            sisfb_scalelcd = scalelcd ^ 1;
5984         }
5985
5986         /* Need to check crt2 type first for fstn/dstn */
5987
5988         if(forcecrt2type)
5989                 sisfb_search_crt2type(forcecrt2type);
5990
5991         if(tvstandard)
5992                 sisfb_search_tvstd(tvstandard);
5993
5994         if(mode)
5995                 sisfb_search_mode(mode, FALSE);
5996         else if(vesa != -1)
5997                 sisfb_search_vesamode(vesa, FALSE);
5998
5999         sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6000
6001         sisfb_forcecrt1 = forcecrt1;
6002         if(forcecrt1 == 1)      sisfb_crt1off = 0;
6003         else if(forcecrt1 == 0) sisfb_crt1off = 1;
6004
6005         if(noaccel == 1)      sisfb_accel = 0;
6006         else if(noaccel == 0) sisfb_accel = 1;
6007
6008         if(noypan == 1)       sisfb_ypan = 0;
6009         else if(noypan == 0)  sisfb_ypan = 1;
6010
6011         if(nomax == 1)        sisfb_max = 0;
6012         else if(nomax == 0)   sisfb_max = 1;
6013         
6014 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6015         if(inverse)           sisfb_inverse = 1;
6016 #endif
6017
6018         if(mem)               sisfb_parm_mem = mem;
6019
6020         if(userom != -1)      sisfb_userom = userom;
6021         if(useoem != -1)      sisfb_useoem = useoem;
6022
6023         if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
6024         if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
6025
6026         sisfb_nocrt2rate = nocrt2rate;
6027
6028         if(specialtiming)
6029                 sisfb_search_specialtiming(specialtiming);
6030
6031         if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
6032
6033         if(filter != -1) sisfb_filter = filter;
6034
6035         sisfb_tvxposoffset = tvxposoffset;
6036         sisfb_tvyposoffset = tvyposoffset;
6037
6038 #if !defined(__i386__) && !defined(__x86_64__)
6039         sisfb_resetcard = (resetcard) ? 1 : 0;
6040         if(videoram)    sisfb_videoram = videoram;
6041 #endif
6042
6043         return(sisfb_init());
6044 }
6045
6046 static void __exit sisfb_remove_module(void)
6047 {
6048         pci_unregister_driver(&sisfb_driver);
6049         printk(KERN_DEBUG "sisfb: Module unloaded\n");
6050 }
6051
6052 module_init(sisfb_init_module);
6053 module_exit(sisfb_remove_module);
6054
6055 #endif     /*  /MODULE  */
6056
6057 EXPORT_SYMBOL(sis_malloc);
6058 EXPORT_SYMBOL(sis_free);
6059
6060