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