VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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 char * __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         unsigned char *rom_base, *rom;
3962         int  romptr;
3963         unsigned short pciid;
3964
3965         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
3966
3967             rom_base = (unsigned char *)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         unsigned char *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, ULONG 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         ULONG   FBAddr = (ULONG)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 *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_vbase = ivideo->bios_abase = NULL;
4997         if(ivideo->sisfb_userom) {
4998             ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
4999 #if defined(__i386__) || defined(__x86_64__)
5000             ivideo->bios_vbase = ivideo->sishw_ext.pjVirtualRomBase;    /* mapped */
5001 #else
5002             ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;    /* allocated */
5003 #endif
5004             if(ivideo->sishw_ext.pjVirtualRomBase) {
5005                 printk(KERN_INFO "sisfb: Video ROM found and %s to 0x%p\n",
5006                         ivideo->bios_vbase ? "mapped" : "copied",
5007                         ivideo->sishw_ext.pjVirtualRomBase);
5008                 ivideo->sishw_ext.UseROM = TRUE;
5009             } else {
5010                 ivideo->sishw_ext.UseROM = FALSE;
5011                 printk(KERN_INFO "sisfb: Video ROM not found\n");
5012             }
5013         } else {
5014             ivideo->sishw_ext.pjVirtualRomBase = NULL;
5015             ivideo->sishw_ext.UseROM = FALSE;
5016             printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
5017         }
5018
5019         /* Find systems for special custom timing */
5020         if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
5021            int j;
5022            unsigned char *biosver = NULL;
5023            unsigned char *biosdate = NULL;
5024            BOOLEAN footprint;
5025            u32 chksum = 0;
5026
5027            if(ivideo->sishw_ext.UseROM) {
5028               biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
5029               biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
5030               for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
5031            }
5032
5033            i=0;
5034            do {
5035               if( (mycustomttable[i].chipID == ivideo->chip) &&
5036                   ((!strlen(mycustomttable[i].biosversion)) ||
5037                    (ivideo->sishw_ext.UseROM &&
5038                    (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
5039                   ((!strlen(mycustomttable[i].biosdate)) ||
5040                    (ivideo->sishw_ext.UseROM &&
5041                    (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
5042                   ((!mycustomttable[i].bioschksum) ||
5043                    (ivideo->sishw_ext.UseROM &&
5044                    (mycustomttable[i].bioschksum == chksum)))   &&
5045                   (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
5046                   (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
5047                  footprint = TRUE;
5048                  for(j = 0; j < 5; j++) {
5049                     if(mycustomttable[i].biosFootprintAddr[j]) {
5050                        if(ivideo->sishw_ext.UseROM) {
5051                           if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
5052                                 mycustomttable[i].biosFootprintData[j]) {
5053                              footprint = FALSE;
5054                           }
5055                        } else footprint = FALSE;
5056                     }
5057                  }
5058                  if(footprint) {
5059                     ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
5060                     printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
5061                         mycustomttable[i].vendorName,
5062                         mycustomttable[i].cardName);
5063                     printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
5064                         mycustomttable[i].optionName);
5065                     break;
5066                  }
5067               }
5068               i++;
5069            } while(mycustomttable[i].chipID);
5070         }
5071
5072 #ifdef CONFIG_FB_SIS_300
5073         if(ivideo->sisvga_engine == SIS_300_VGA) {
5074                 if( (!sisvga_enabled)
5075 #if !defined(__i386__) && !defined(__x86_64__)
5076                                       || (sisfb_resetcard)
5077 #endif
5078                                                            ) {
5079                         if(ivideo->chip == SIS_300) {
5080                                 sisfb_post_sis300(pdev);
5081                         }
5082                 }
5083         }
5084 #endif
5085
5086 #ifdef CONFIG_FB_SIS_315
5087         if(ivideo->sisvga_engine == SIS_315_VGA) {
5088                 if( (!sisvga_enabled)
5089 #if !defined(__i386__) && !defined(__x86_64__)
5090                                      || (sisfb_resetcard)
5091 #endif
5092                                                           ) {
5093                         if((ivideo->chip == SIS_315H)   ||
5094                            (ivideo->chip == SIS_315)    ||
5095                            (ivideo->chip == SIS_315PRO) ||
5096                            (ivideo->chip == SIS_330)) {
5097                                 sisfb_post_sis315330(pdev);
5098                         }
5099                 }
5100         }
5101 #endif
5102
5103         if(sisfb_get_dram_size(ivideo)) {
5104                 printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
5105                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5106                 pci_set_drvdata(pdev, NULL);
5107                 kfree(sis_fb_info);
5108                 return -ENODEV;
5109         }
5110
5111         if((ivideo->sisfb_mode_idx < 0) ||
5112            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5113                 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
5114                 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
5115                 /* Enable 2D accelerator engine */
5116                 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
5117         }
5118
5119         if(sisfb_pdc != 0xff) {
5120            if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
5121            else                                     sisfb_pdc &= 0x1f;
5122            ivideo->SiS_Pr.PDC = sisfb_pdc;
5123         }
5124 #ifdef CONFIG_FB_SIS_315
5125         if(ivideo->sisvga_engine == SIS_315_VGA) {
5126            if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
5127         }
5128 #endif
5129
5130         if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
5131                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
5132                 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
5133                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5134                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5135                 pci_set_drvdata(pdev, NULL);
5136                 kfree(sis_fb_info);
5137                 return -ENODEV;
5138         }
5139
5140         if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
5141                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
5142                 release_mem_region(ivideo->video_base, ivideo->video_size);
5143                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5144                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5145                 pci_set_drvdata(pdev, NULL);
5146                 kfree(sis_fb_info);
5147                 return -ENODEV;
5148         }
5149
5150         ivideo->video_vbase = (unsigned long)ioremap(ivideo->video_base, ivideo->video_size);
5151         ivideo->sishw_ext.pjVideoMemoryAddress = (unsigned char *)ivideo->video_vbase;
5152         if(!ivideo->video_vbase) {
5153                 printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
5154                 release_mem_region(ivideo->video_base, ivideo->video_size);
5155                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5156                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5157                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5158                 pci_set_drvdata(pdev, NULL);
5159                 kfree(sis_fb_info);
5160                 return -ENODEV;
5161         }
5162
5163         ivideo->mmio_vbase = (unsigned long)ioremap(ivideo->mmio_base, ivideo->mmio_size);
5164         if(!ivideo->mmio_vbase) {
5165                 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
5166                 iounmap((void *)ivideo->video_vbase);
5167                 release_mem_region(ivideo->video_base, ivideo->video_size);
5168                 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5169                 if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5170                 if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5171                 pci_set_drvdata(pdev, NULL);
5172                 kfree(sis_fb_info);
5173                 return -ENODEV;
5174         }
5175
5176         printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
5177                 ivideo->video_base, ivideo->video_vbase, ivideo->video_size / 1024);
5178
5179         printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
5180                 ivideo->mmio_base, ivideo->mmio_vbase, ivideo->mmio_size / 1024);
5181
5182         if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
5183                 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
5184         }
5185
5186         /* Used for clearing the screen only, therefore respect our mem limit */
5187         ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
5188
5189         ivideo->mtrr = 0;
5190
5191         ivideo->vbflags = 0;
5192         ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
5193         ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
5194         ivideo->defmodeidx    = DEFAULT_MODE;
5195
5196         ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
5197
5198         if((ivideo->sisfb_mode_idx < 0) ||
5199            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
5200
5201                 sisfb_sense_crt1(ivideo);
5202
5203                 sisfb_get_VB_type(ivideo);
5204
5205                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5206                         sisfb_detect_VB_connect(ivideo);
5207                 }
5208
5209                 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
5210
5211                 if(ivideo->vbflags & VB_VIDEOBRIDGE) {
5212                    if(ivideo->sisfb_crt2type != -1) {
5213                       if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
5214                          ivideo->currentvbflags |= CRT2_LCD;
5215                       } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
5216                          ivideo->currentvbflags |= ivideo->sisfb_crt2type;
5217                       }
5218                    } else {
5219                       /* Chrontel 700x TV detection often unreliable, therefore use a
5220                        * different default order on such machines
5221                        */
5222                       if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
5223                          if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
5224                          else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
5225                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5226                       } else {
5227                          if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
5228                          else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
5229                          else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
5230                       }
5231                    }
5232                 }
5233
5234                 if(ivideo->vbflags & CRT2_LCD) {
5235                    inSISIDXREG(SISCR, 0x36, reg);
5236                    reg &= 0x0f;
5237                    if(ivideo->sisvga_engine == SIS_300_VGA) {
5238                       ivideo->sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
5239                    } else if(ivideo->chip >= SIS_661) {
5240                       ivideo->sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
5241                    } else {
5242                       ivideo->sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
5243                       if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
5244                          if((ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_2) &&
5245                             (ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_3)) {
5246                             ivideo->sishw_ext.ulCRT2LCDType = LCD_320x480;
5247                          }
5248                       }
5249                    }
5250                    if(ivideo->sishw_ext.ulCRT2LCDType == LCD_UNKNOWN) {
5251                       ivideo->sishw_ext.ulCRT2LCDType = LCD_1024x768;
5252                       printk(KERN_DEBUG "sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg);
5253                    }
5254                    for(i = 0; i < SIS_LCD_NUMBER; i++) {
5255                       if(ivideo->sishw_ext.ulCRT2LCDType == sis_lcd_data[i].lcdtype) {
5256                          ivideo->lcdxres = sis_lcd_data[i].xres;
5257                          ivideo->lcdyres = sis_lcd_data[i].yres;
5258                          ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
5259                          break;
5260                       }
5261                    }
5262                    if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
5263                         ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
5264                    } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
5265                         ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
5266                    }
5267                    printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
5268                                 ivideo->lcdxres, ivideo->lcdyres);
5269                 }
5270
5271 #ifdef CONFIG_FB_SIS_300
5272                 /* Save the current PanelDelayCompensation if the LCD is currently used */
5273                 if(ivideo->sisvga_engine == SIS_300_VGA) {
5274                    if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
5275                        int tmp;
5276                        inSISIDXREG(SISCR,0x30,tmp);
5277                        if(tmp & 0x20) {
5278                           /* Currently on LCD? If yes, read current pdc */
5279                           inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
5280                           ivideo->detectedpdc &= 0x3c;
5281                           if(ivideo->SiS_Pr.PDC == -1) {
5282                              /* Let option override detection */
5283                              ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5284                           }
5285                           printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
5286                                  ivideo->detectedpdc);
5287                        }
5288                        if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5289                           printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
5290                                  ivideo->SiS_Pr.PDC);
5291                        }
5292                    }
5293                 }
5294 #endif
5295
5296 #ifdef CONFIG_FB_SIS_315
5297                 if(ivideo->sisvga_engine == SIS_315_VGA) {
5298
5299                    /* Try to find about LCDA */
5300                    if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
5301                       int tmp;
5302                       inSISIDXREG(SISPART1,0x13,tmp);
5303                       if(tmp & 0x04) {
5304                          ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
5305                          ivideo->detectedlcda = 0x03;
5306                       }
5307                    }
5308
5309                    /* Save PDC */
5310                    if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
5311                       int tmp;
5312                       inSISIDXREG(SISCR,0x30,tmp);
5313                       if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5314                          /* Currently on LCD? If yes, read current pdc */
5315                          u8 pdc;
5316                          inSISIDXREG(SISPART1,0x2D,pdc);
5317                          ivideo->detectedpdc  = (pdc & 0x0f) << 1;
5318                          ivideo->detectedpdca = (pdc & 0xf0) >> 3;
5319                          inSISIDXREG(SISPART1,0x35,pdc);
5320                          ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
5321                          inSISIDXREG(SISPART1,0x20,pdc);
5322                          ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
5323                          if(ivideo->newrom) {
5324                             /* New ROM invalidates other PDC resp. */
5325                             if(ivideo->detectedlcda != 0xff) {
5326                                ivideo->detectedpdc = 0xff;
5327                             } else {
5328                                ivideo->detectedpdca = 0xff;
5329                             }
5330                          }
5331                          if(ivideo->SiS_Pr.PDC == -1) {
5332                             if(ivideo->detectedpdc != 0xff) {
5333                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
5334                             }
5335                          }
5336                          if(ivideo->SiS_Pr.PDCA == -1) {
5337                             if(ivideo->detectedpdca != 0xff) {
5338                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
5339                             }
5340                          }
5341                          if(ivideo->detectedpdc != 0xff) {
5342                             printk(KERN_INFO
5343                                  "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
5344                                   ivideo->detectedpdc);
5345                          }
5346                          if(ivideo->detectedpdca != 0xff) {
5347                             printk(KERN_INFO
5348                                  "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
5349                                   ivideo->detectedpdca);
5350                          }
5351                       }
5352
5353                       /* Save EMI */
5354                       if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
5355                          inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
5356                          inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
5357                          inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
5358                          inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
5359                          ivideo->SiS_Pr.HaveEMI = TRUE;
5360                          if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
5361                                 ivideo->SiS_Pr.HaveEMILCD = TRUE;
5362                          }
5363                       }
5364                    }
5365
5366                    /* Let user override detected PDCs (all bridges) */
5367                    if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
5368                       if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
5369                          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
5370                                  ivideo->SiS_Pr.PDC);
5371                       }
5372                       if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
5373                          printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
5374                                  ivideo->SiS_Pr.PDCA);
5375                       }
5376                    }
5377
5378                 }
5379 #endif
5380
5381                 if(!ivideo->sisfb_crt1off) {
5382                         sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
5383                 } else {
5384                         if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
5385                            (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
5386                                 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
5387                         }
5388                 }
5389
5390                 if(ivideo->sisfb_mode_idx >= 0) {
5391                         int bu = ivideo->sisfb_mode_idx;
5392                         ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
5393                                         ivideo->sisfb_mode_idx, ivideo->currentvbflags);
5394                         if(bu != ivideo->sisfb_mode_idx) {
5395                                 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
5396                                         sisbios_mode[bu].xres,
5397                                         sisbios_mode[bu].yres,
5398                                         sisbios_mode[bu].bpp);
5399                         }
5400                 }
5401
5402                 if(ivideo->sisfb_mode_idx < 0) {
5403                         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
5404                            case CRT2_LCD:
5405                                 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
5406                                 break;
5407                            case CRT2_TV:
5408                                 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
5409                                 break;
5410                            default:
5411                                 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
5412                                 break;
5413                         }
5414                 }
5415
5416                 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
5417
5418                 if(ivideo->refresh_rate != 0) {
5419                         sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
5420                 }
5421
5422                 if(ivideo->rate_idx == 0) {
5423                         ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
5424                         ivideo->refresh_rate = 60;
5425                 }
5426
5427                 if(ivideo->sisfb_thismonitor.datavalid) {
5428                         if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
5429                                               ivideo->rate_idx, ivideo->refresh_rate)) {
5430                                 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
5431                         }
5432                 }
5433
5434                 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
5435                 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
5436                 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
5437
5438                 sisfb_set_vparms(ivideo);
5439                 
5440 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  
5441
5442                 /* ---------------- For 2.4: Now switch the mode ------------------ */          
5443                 
5444                 printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
5445                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5446                         ivideo->refresh_rate);
5447
5448                 sisfb_pre_setmode(ivideo);
5449
5450                 if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
5451                         printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
5452                                                                         ivideo->mode_no);
5453                         iounmap((void *)ivideo->video_vbase);
5454                         iounmap((void *)ivideo->mmio_vbase);
5455                         release_mem_region(ivideo->video_base, ivideo->video_size);
5456                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5457                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5458                         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5459                         pci_set_drvdata(pdev, NULL);
5460                         kfree(sis_fb_info);
5461                         return -EINVAL;
5462                 }
5463
5464                 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
5465
5466                 sisfb_post_setmode(ivideo);
5467
5468                 /* Maximize regardless of sisfb_max at startup */
5469                 ivideo->default_var.yres_virtual = 32767;
5470
5471                 /* Force reset of x virtual in crtc_to_var */
5472                 ivideo->default_var.xres_virtual = 0;
5473
5474                 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
5475
5476                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5477                 sisfb_set_pitch(ivideo);
5478
5479                 ivideo->accel = 0;
5480                 if(ivideo->sisfb_accel) {
5481                    ivideo->accel = -1;
5482                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5483                 }
5484                 sisfb_initaccel(ivideo);
5485                 
5486                 sis_fb_info->node  = -1;
5487                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5488                 sis_fb_info->fbops = &sisfb_ops;
5489                 sis_fb_info->disp  = &ivideo->sis_disp;
5490                 sis_fb_info->blank = &sisfb_blank;
5491                 sis_fb_info->switch_con = &sisfb_switch;
5492                 sis_fb_info->updatevar  = &sisfb_update_var;
5493                 sis_fb_info->changevar  = NULL;
5494                 strcpy(sis_fb_info->fontname, sisfb_fontname);
5495
5496                 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
5497
5498 #else           /* --------- For 2.6: Setup a somewhat sane default var ------------ */
5499
5500                 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
5501                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
5502                         ivideo->refresh_rate);
5503
5504                 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
5505                 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
5506                 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
5507
5508                 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
5509                 
5510                 ivideo->default_var.pixclock = (u32) (1000000000 /
5511                                 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5512                                                 ivideo->mode_no, ivideo->rate_idx));
5513                                                 
5514                 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
5515                                 ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
5516                    if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
5517                       ivideo->default_var.pixclock <<= 1;
5518                    }
5519                 }
5520
5521                 if(ivideo->sisfb_ypan) {
5522                    /* Maximize regardless of sisfb_max at startup */
5523                    ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
5524                    if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
5525                       ivideo->default_var.yres_virtual = ivideo->default_var.yres;
5526                    }
5527                 }
5528
5529                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
5530
5531                 ivideo->accel = 0;
5532                 if(ivideo->sisfb_accel) {
5533                    ivideo->accel = -1;
5534 #ifdef STUPID_ACCELF_TEXT_SHIT
5535                    ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
5536 #endif
5537                 }
5538                 sisfb_initaccel(ivideo);
5539
5540 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
5541                 sis_fb_info->flags = FBINFO_DEFAULT             |
5542                                      FBINFO_HWACCEL_YPAN        |
5543                                      FBINFO_HWACCEL_XPAN        |
5544                                      FBINFO_HWACCEL_COPYAREA    |
5545                                      FBINFO_HWACCEL_FILLRECT    |
5546                                      ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
5547 #else
5548                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
5549 #endif
5550                 sis_fb_info->var = ivideo->default_var;
5551                 sis_fb_info->fix = ivideo->sisfb_fix;
5552                 sis_fb_info->screen_base = (char *)ivideo->video_vbase;
5553                 sis_fb_info->fbops = &sisfb_ops;
5554
5555                 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
5556                 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
5557                 
5558                 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
5559 #endif          /* 2.6 */
5560
5561                 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
5562
5563 #ifdef CONFIG_MTRR
5564                 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
5565                                         MTRR_TYPE_WRCOMB, 1);
5566                 if(!ivideo->mtrr) {
5567                         printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
5568                 }
5569 #endif
5570
5571 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5572                 vc_resize_con(1, 1, 0);
5573 #endif
5574
5575                 if(register_framebuffer(sis_fb_info) < 0) {
5576                         printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
5577                         iounmap((void *)ivideo->video_vbase);
5578                         iounmap((void *)ivideo->mmio_vbase);
5579                         release_mem_region(ivideo->video_base, ivideo->video_size);
5580                         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5581                         if(ivideo->bios_abase) vfree(ivideo->bios_abase);
5582                         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5583                         pci_set_drvdata(pdev, NULL);
5584                         kfree(sis_fb_info);
5585                         return -EINVAL;
5586                 }
5587
5588                 ivideo->registered = 1;
5589
5590                 /* Enlist us */
5591                 ivideo->next = card_list;
5592                 card_list = ivideo;
5593
5594 #ifdef SIS_CONFIG_COMPAT
5595                 {
5596                 int ret;
5597                 /* Our ioctls are all "32/64bit compatible" */
5598                 if(register_ioctl32_conversion(FBIOGET_VBLANK, NULL)) {
5599                    printk(KERN_ERR "sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
5600                 } else {
5601                    ivideo->ioctl32vblankregistered = 1;
5602                 }
5603                 ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
5604                 ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
5605                 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
5606                 ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
5607                 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
5608                 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
5609                 ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
5610                 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
5611                 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
5612                 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
5613                 if(ret) printk(KERN_ERR "sisfb: Error registering ioctl32 translations\n");
5614                 else    ivideo->ioctl32registered = 1;
5615                 }
5616 #endif
5617
5618                 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
5619                      ivideo->sisfb_accel ? "enabled" : "disabled",
5620                      ivideo->sisfb_ypan  ?
5621                         (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
5622
5623
5624                 printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
5625 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5626                         GET_FB_IDX(sis_fb_info->node),
5627 #else
5628                         sis_fb_info->node,
5629 #endif
5630                         ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
5631
5632                 printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
5633
5634         }       /* if mode = "none" */
5635
5636         return 0;
5637 }
5638
5639 /*****************************************************/
5640 /*                PCI DEVICE HANDLING                */
5641 /*****************************************************/
5642
5643 static void __devexit sisfb_remove(struct pci_dev *pdev)
5644 {
5645         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5646         struct fb_info        *sis_fb_info = ivideo->memyselfandi;
5647         int                   registered = ivideo->registered;
5648
5649 #ifdef SIS_CONFIG_COMPAT
5650         if(ivideo->ioctl32vblankregistered) {
5651                 if(unregister_ioctl32_conversion(FBIOGET_VBLANK)) {
5652                         printk(KERN_ERR "sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
5653                 }
5654         }
5655         if(ivideo->ioctl32registered) {
5656                 int ret;
5657                 ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
5658                 ret |= unregister_ioctl32_conversion(FBIO_FREE);
5659                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
5660                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
5661                 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
5662                 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
5663                 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
5664                 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
5665                 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
5666                 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
5667                 if(ret) printk(KERN_ERR "sisfb: Error unregistering ioctl32 translations\n");
5668         }
5669 #endif
5670
5671         /* Unmap */
5672         iounmap((void *)ivideo->video_vbase);
5673         iounmap((void *)ivideo->mmio_vbase);
5674         if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
5675         if(ivideo->bios_abase)    vfree(ivideo->bios_abase);
5676
5677         /* Release mem regions */
5678         release_mem_region(ivideo->video_base, ivideo->video_size);
5679         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
5680
5681 #ifdef CONFIG_MTRR
5682         /* Release MTRR region */
5683         if(ivideo->mtrr) {
5684                 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
5685         }
5686 #endif
5687
5688         /* Unregister the framebuffer */
5689         if(ivideo->registered) {
5690                 unregister_framebuffer(sis_fb_info);
5691 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5692                 framebuffer_release(sis_fb_info);
5693 #else
5694                 kfree(sis_fb_info);
5695 #endif
5696         }
5697
5698         pci_set_drvdata(pdev, NULL);
5699
5700         /* TODO: Restore the initial mode
5701          * This sounds easy but is as good as impossible
5702          * on many machines with SiS chip and video bridge
5703          * since text modes are always set up differently
5704          * from machine to machine. Depends on the type
5705          * of integration between chipset and bridge.
5706          */
5707         if(registered) {
5708            printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
5709         }
5710 };
5711
5712 static struct pci_driver sisfb_driver = {
5713         .name           = "sisfb",
5714         .id_table       = sisfb_pci_table,
5715         .probe          = sisfb_probe,
5716         .remove         = __devexit_p(sisfb_remove)
5717 };
5718
5719 int __init sisfb_init(void)
5720 {
5721         return(pci_module_init(&sisfb_driver));
5722 }
5723
5724 /*****************************************************/
5725 /*                      MODULE                       */
5726 /*****************************************************/
5727
5728 #ifdef MODULE
5729
5730 static char         *mode = NULL;
5731 static int          vesa = -1;
5732 static unsigned int rate = 0;
5733 static unsigned int crt1off = 1;
5734 static unsigned int mem = 0;
5735 static char         *forcecrt2type = NULL;
5736 static int          forcecrt1 = -1;
5737 static int          pdc = -1;
5738 static int          pdc1 = -1;
5739 static int          noaccel = -1;
5740 static int          noypan  = -1;
5741 static int          nomax = -1;
5742 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5743 static int          inverse = 0;
5744 #endif
5745 static int          userom = -1;
5746 static int          useoem = -1;
5747 static char         *tvstandard = NULL;
5748 static int          nocrt2rate = 0;
5749 static int          scalelcd = -1;
5750 static char         *specialtiming = NULL;
5751 static int          lvdshl = -1;
5752 static int          tvxposoffset = 0, tvyposoffset = 0;
5753 static int          filter = -1;
5754 #if !defined(__i386__) && !defined(__x86_64__)
5755 static int          resetcard = 0;
5756 static int          videoram = 0;
5757 #endif
5758
5759 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
5760 MODULE_LICENSE("GPL");
5761 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
5762
5763 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5764 MODULE_PARM(mem, "i");
5765 MODULE_PARM(noaccel, "i");
5766 MODULE_PARM(noypan, "i");
5767 MODULE_PARM(nomax, "i");
5768 MODULE_PARM(userom, "i");
5769 MODULE_PARM(useoem, "i");
5770 MODULE_PARM(mode, "s");
5771 MODULE_PARM(vesa, "i");
5772 MODULE_PARM(rate, "i");
5773 MODULE_PARM(forcecrt1, "i");
5774 MODULE_PARM(forcecrt2type, "s");
5775 MODULE_PARM(scalelcd, "i");
5776 MODULE_PARM(pdc, "i");
5777 MODULE_PARM(pdc1, "i");
5778 MODULE_PARM(specialtiming, "s");
5779 MODULE_PARM(lvdshl, "i");
5780 MODULE_PARM(tvstandard, "s");
5781 MODULE_PARM(tvxposoffset, "i");
5782 MODULE_PARM(tvyposoffset, "i");
5783 MODULE_PARM(filter, "i");
5784 MODULE_PARM(nocrt2rate, "i");
5785 MODULE_PARM(inverse, "i");
5786 #if !defined(__i386__) && !defined(__x86_64__)
5787 MODULE_PARM(resetcard, "i");
5788 MODULE_PARM(videoram, "i");
5789 #endif
5790 #endif
5791
5792 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5793 module_param(mem, int, 0);
5794 module_param(noaccel, int, 0);
5795 module_param(noypan, int, 0);
5796 module_param(nomax, int, 0);
5797 module_param(userom, int, 0);
5798 module_param(useoem, int, 0);
5799 module_param(mode, charp, 0);
5800 module_param(vesa, int, 0);
5801 module_param(rate, int, 0);
5802 module_param(forcecrt1, int, 0);
5803 module_param(forcecrt2type, charp, 0);
5804 module_param(scalelcd, int, 0);
5805 module_param(pdc, int, 0);
5806 module_param(pdc1, int, 0);
5807 module_param(specialtiming, charp, 0);
5808 module_param(lvdshl, int, 0);
5809 module_param(tvstandard, charp, 0);
5810 module_param(tvxposoffset, int, 0);
5811 module_param(tvyposoffset, int, 0);
5812 module_param(filter, int, 0);
5813 module_param(nocrt2rate, int, 0);
5814 #if !defined(__i386__) && !defined(__x86_64__)
5815 module_param(resetcard, int, 0);
5816 module_param(videoram, int, 0);
5817 #endif
5818 #endif
5819
5820 MODULE_PARM_DESC(mem,
5821         "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
5822           "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
5823           "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
5824           "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
5825           "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
5826           "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
5827           "for XFree86 4.x/X.org 6.7 and later.\n");
5828
5829 MODULE_PARM_DESC(noaccel,
5830         "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
5831           "(default: 0)\n");
5832
5833 MODULE_PARM_DESC(noypan,
5834         "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
5835           "will be performed by redrawing the screen. (default: 0)\n");
5836
5837 MODULE_PARM_DESC(nomax,
5838         "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
5839           "memory for the virtual screen in order to optimize scrolling performance. If\n"
5840           "this is set to anything other than 0, sisfb will not do this and thereby \n"
5841           "enable the user to positively specify a virtual Y size of the screen using\n"
5842           "fbset. (default: 0)\n");
5843
5844 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5845 MODULE_PARM_DESC(mode,
5846         "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
5847           "1024x768x16. Other formats supported include XxY-Depth and\n"
5848           "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
5849           "number, it will be interpreted as a VESA mode number. (default: none if\n"
5850           "sisfb is a module; this leaves the console untouched and the driver will\n"
5851           "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
5852           "is in the kernel)\n");
5853 MODULE_PARM_DESC(vesa,
5854         "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
5855           "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
5856           "and the driver will only do the video memory management for eg. DRM/DRI;\n"
5857           "0x0103 if sisfb is in the kernel)\n");
5858 #endif
5859
5860 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
5861 MODULE_PARM_DESC(mode,
5862        "\nSelects the desired default display mode in the format XxYxDepth,\n"
5863          "eg. 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: 800x600x8)\n");
5866
5867 MODULE_PARM_DESC(vesa,
5868        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
5869          "0x117 (default: 0x0103)\n");
5870 #endif
5871
5872 MODULE_PARM_DESC(rate,
5873         "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
5874           "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
5875           "will be ignored (default: 60)\n");
5876
5877 MODULE_PARM_DESC(forcecrt1,
5878         "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
5879           "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
5880           "0=CRT1 OFF) (default: [autodetected])\n");
5881
5882 MODULE_PARM_DESC(forcecrt2type,
5883         "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
5884           "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
5885           "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
5886           "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
5887           "be used instead of TV to override the TV detection. Furthermore, on systems\n"
5888           "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
5889           "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
5890           "depends on the very hardware in use. (default: [autodetected])\n");
5891
5892 MODULE_PARM_DESC(scalelcd,
5893         "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
5894           "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
5895           "show black bars around the image, TMDS panels will probably do the scaling\n"
5896           "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
5897
5898 MODULE_PARM_DESC(pdc,
5899         "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
5900           "should detect this correctly in most cases; however, sometimes this is not\n"
5901           "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
5902           "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
5903           "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
5904           "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
5905
5906 #ifdef CONFIG_FB_SIS_315
5907 MODULE_PARM_DESC(pdc1,
5908         "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
5909           "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
5910           "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
5911           "implemented yet.\n");
5912 #endif
5913
5914 MODULE_PARM_DESC(specialtiming,
5915         "\nPlease refer to documentation for more information on this option.\n");
5916
5917 MODULE_PARM_DESC(lvdshl,
5918         "\nPlease refer to documentation for more information on this option.\n");
5919
5920 MODULE_PARM_DESC(tvstandard,
5921         "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
5922           "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
5923
5924 MODULE_PARM_DESC(tvxposoffset,
5925         "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
5926           "Default: 0\n");
5927
5928 MODULE_PARM_DESC(tvyposoffset,
5929         "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
5930           "Default: 0\n");
5931
5932 MODULE_PARM_DESC(filter,
5933         "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
5934           "(Possible values 0-7, default: [no filter])\n");
5935
5936 MODULE_PARM_DESC(nocrt2rate,
5937         "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
5938           "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
5939
5940 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5941 MODULE_PARM_DESC(inverse,
5942         "\nSetting this to anything but 0 should invert the display colors, but this\n"
5943           "does not seem to work. (default: 0)\n");
5944 #endif
5945
5946 #if !defined(__i386__) && !defined(__x86_64__)
5947 #ifdef CONFIG_FB_SIS_300
5948 MODULE_PARM_DESC(resetcard,
5949         "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
5950           "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
5951           "Default: 0\n");
5952
5953 MODULE_PARM_DESC(videoram,
5954         "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
5955           "some non-x86 architectures where the memory auto detection fails. Only\n"
5956           "relevant if resetcard is set, too. Default: [auto-detect]\n");
5957 #endif
5958 #endif
5959
5960 int __init sisfb_init_module(void)
5961 {
5962         sisfb_setdefaultparms();
5963
5964         if(rate) sisfb_parm_rate = rate;
5965
5966         if((scalelcd == 0) || (scalelcd == 1)) {
5967            sisfb_scalelcd = scalelcd ^ 1;
5968         }
5969
5970         /* Need to check crt2 type first for fstn/dstn */
5971
5972         if(forcecrt2type)
5973                 sisfb_search_crt2type(forcecrt2type);
5974
5975         if(tvstandard)
5976                 sisfb_search_tvstd(tvstandard);
5977
5978         if(mode)
5979                 sisfb_search_mode(mode, FALSE);
5980         else if(vesa != -1)
5981                 sisfb_search_vesamode(vesa, FALSE);
5982
5983         sisfb_crt1off = (crt1off == 0) ? 1 : 0;
5984
5985         sisfb_forcecrt1 = forcecrt1;
5986         if(forcecrt1 == 1)      sisfb_crt1off = 0;
5987         else if(forcecrt1 == 0) sisfb_crt1off = 1;
5988
5989         if(noaccel == 1)      sisfb_accel = 0;
5990         else if(noaccel == 0) sisfb_accel = 1;
5991
5992         if(noypan == 1)       sisfb_ypan = 0;
5993         else if(noypan == 0)  sisfb_ypan = 1;
5994
5995         if(nomax == 1)        sisfb_max = 0;
5996         else if(nomax == 0)   sisfb_max = 1;
5997         
5998 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
5999         if(inverse)           sisfb_inverse = 1;
6000 #endif
6001
6002         if(mem)               sisfb_parm_mem = mem;
6003
6004         if(userom != -1)      sisfb_userom = userom;
6005         if(useoem != -1)      sisfb_useoem = useoem;
6006
6007         if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
6008         if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
6009
6010         sisfb_nocrt2rate = nocrt2rate;
6011
6012         if(specialtiming)
6013                 sisfb_search_specialtiming(specialtiming);
6014
6015         if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
6016
6017         if(filter != -1) sisfb_filter = filter;
6018
6019         sisfb_tvxposoffset = tvxposoffset;
6020         sisfb_tvyposoffset = tvyposoffset;
6021
6022 #if !defined(__i386__) && !defined(__x86_64__)
6023         sisfb_resetcard = (resetcard) ? 1 : 0;
6024         if(videoram)    sisfb_videoram = videoram;
6025 #endif
6026
6027         return(sisfb_init());
6028 }
6029
6030 static void __exit sisfb_remove_module(void)
6031 {
6032         pci_unregister_driver(&sisfb_driver);
6033         printk(KERN_DEBUG "sisfb: Module unloaded\n");
6034 }
6035
6036 module_init(sisfb_init_module);
6037 module_exit(sisfb_remove_module);
6038
6039 #endif     /*  /MODULE  */
6040
6041 EXPORT_SYMBOL(sis_malloc);
6042 EXPORT_SYMBOL(sis_free);
6043
6044