⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sis_main.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * SiS 300/305/540/630(S)/730(S) * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 * * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the named License, * or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Author:   	Thomas Winischhofer <thomas@winischhofer.net> * * Author of (practically wiped) code base: *		SiS (www.sis.com) *	 	Copyright (C) 1999 Silicon Integrated Systems, Inc. * * See http://www.winischhofer.net/ for more information and updates * * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver, * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#include <linux/moduleparam.h>#endif#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/console.h>#include <linux/selection.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/vt_kern.h>#include <linux/capability.h>#include <linux/fs.h>#include <linux/types.h>#include <asm/uaccess.h>#include <asm/io.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#endif#include "sis.h"#include "sis_main.h"#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)#error "This version of sisfb requires at least 2.6.3"#endif#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#ifdef FBCON_HAS_CFB8extern struct display_switch fbcon_sis8;#endif#ifdef FBCON_HAS_CFB16extern struct display_switch fbcon_sis16;#endif#ifdef FBCON_HAS_CFB32extern struct display_switch fbcon_sis32;#endif#endif/* ------------------ Internal helper routines ----------------- */static void __initsisfb_setdefaultparms(void){	sisfb_off 		= 0;	sisfb_parm_mem 		= 0;	sisfb_accel 		= -1;	sisfb_ypan      	= -1;	sisfb_max 		= -1;	sisfb_userom    	= -1;        sisfb_useoem    	= -1;#ifdef MODULE	/* Module: "None" for 2.4, default mode for 2.5+ */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	sisfb_mode_idx 		= -1;#else	sisfb_mode_idx  	= MODE_INDEX_NONE;#endif#else	/* Static: Default mode */	sisfb_mode_idx  	= -1;#endif	sisfb_parm_rate 	= -1;	sisfb_crt1off 		= 0;	sisfb_forcecrt1 	= -1;	sisfb_crt2type  	= -1;	sisfb_crt2flags 	= 0;	sisfb_pdc 		= 0xff;	sisfb_pdca 		= 0xff;	sisfb_scalelcd  	= -1;	sisfb_specialtiming 	= CUT_NONE;	sisfb_lvdshl 		= -1;	sisfb_dstn     		= 0;	sisfb_fstn 		= 0;	sisfb_tvplug    	= -1;	sisfb_tvstd     	= -1;	sisfb_tvxposoffset 	= 0;	sisfb_tvyposoffset 	= 0;	sisfb_filter 		= -1;	sisfb_nocrt2rate 	= 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	sisfb_inverse   	= 0;	sisfb_fontname[0] 	= 0;#endif#if !defined(__i386__) && !defined(__x86_64__)	sisfb_resetcard 	= 0;	sisfb_videoram  	= 0;#endif}static void __initsisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet){	int i = 0, j = 0;	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */	if(vesamode == 0) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		sisfb_mode_idx = MODE_INDEX_NONE;#else		if(!quiet) {		   printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");		}		sisfb_mode_idx = DEFAULT_MODE;#endif		return;	}	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */	while(sisbios_mode[i++].mode_no[0] != 0) {		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {		    if(sisfb_fstn) {		       if(sisbios_mode[i-1].mode_no[1] == 0x50 ||		          sisbios_mode[i-1].mode_no[1] == 0x56 ||		          sisbios_mode[i-1].mode_no[1] == 0x53) continue;	            } else {		       if(sisbios_mode[i-1].mode_no[1] == 0x5a ||		          sisbios_mode[i-1].mode_no[1] == 0x5b) continue;		    }		    sisfb_mode_idx = i - 1;		    j = 1;		    break;		}	}	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);}static voidsisfb_search_mode(char *name, BOOLEAN quiet){	int i = 0;	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;	char strbuf[16], strbuf1[20];	char *nameptr = name;	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */	if(name == NULL) {	   if(!quiet) {	      printk(KERN_ERR "sisfb: Internal error, using default mode.\n");	   }	   sisfb_mode_idx = DEFAULT_MODE;	   return;	}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)        if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {	   if(!quiet) {	      printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");	   }	   sisfb_mode_idx = DEFAULT_MODE;	   return;	}#endif	if(strlen(name) <= 19) {	   strcpy(strbuf1, name);	   for(i=0; i<strlen(strbuf1); i++) {	      if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';	   }	   /* This does some fuzzy mode naming detection */	   if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {	      if((rate <= 32) || (depth > 32)) {	         j = rate; rate = depth; depth = j;	      }	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);	      nameptr = strbuf;	      sisfb_parm_rate = rate;	   } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);	      nameptr = strbuf;	   } else {	      xres = 0;	      if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {	         sprintf(strbuf, "%ux%ux8", xres, yres);	         nameptr = strbuf;	      } else {	         sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);	         return;	      }	   }	}	i = 0; j = 0;	while(sisbios_mode[i].mode_no[0] != 0) {		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {		   	if(sisfb_fstn) {		      		if(sisbios_mode[i-1].mode_no[1] == 0x50 ||		         	   sisbios_mode[i-1].mode_no[1] == 0x56 ||		         	   sisbios_mode[i-1].mode_no[1] == 0x53) continue;	           	} else {		      		if(sisbios_mode[i-1].mode_no[1] == 0x5a ||		         	   sisbios_mode[i-1].mode_no[1] == 0x5b) continue;		   	}		   	sisfb_mode_idx = i - 1;		   	j = 1;		   	break;		}	}	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);}#ifndef MODULEstatic void __devinitsisfb_get_vga_mode_from_kernel(void){#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)   	char mymode[32];	int  mydepth = screen_info.lfb_depth;	if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;	if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&	    (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&	    (mydepth >= 8) && (mydepth <= 32) ) {	    if(mydepth == 24) mydepth = 32;	    sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,	    				screen_info.lfb_height,					mydepth);	    printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);	    sisfb_search_mode(mymode, TRUE);	}#endif	return;}#endifstatic void __initsisfb_search_crt2type(const char *name){	int i = 0;	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */	if(name == NULL) return;	while(sis_crt2type[i].type_no != -1) {	   	if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {	      		sisfb_crt2type = sis_crt2type[i].type_no;	      		sisfb_tvplug = sis_crt2type[i].tvplug_no;	      		sisfb_crt2flags = sis_crt2type[i].flags;	      		break;	   	}	   	i++;	}	sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;	sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;	if(sisfb_crt2type < 0) {		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);	}}static void __initsisfb_search_tvstd(const char *name){	int i = 0;	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */	if(name == NULL) return;	while(sis_tvtype[i].type_no != -1) {	   	if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {	      		sisfb_tvstd = sis_tvtype[i].type_no;	      		break;	   	}	   	i++;	}}static void __initsisfb_search_specialtiming(const char *name){	int i = 0;	BOOLEAN found = FALSE;	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */	if(name == NULL) return;	if(!strnicmp(name, "none", 4)) {	        sisfb_specialtiming = CUT_FORCENONE;		printk(KERN_DEBUG "sisfb: Special timing disabled\n");	} else {	   while(mycustomttable[i].chipID != 0) {	      if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {		 sisfb_specialtiming = mycustomttable[i].SpecialID;		 found = TRUE;		 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",		 	mycustomttable[i].vendorName, mycustomttable[i].cardName,		 	mycustomttable[i].optionName);		 break;	      }	      i++;	   }	   if(!found) {	      printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");	      printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");	      i = 0;	      while(mycustomttable[i].chipID != 0) {		 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",		     mycustomttable[i].optionName,		     mycustomttable[i].vendorName,		     mycustomttable[i].cardName);		 i++;	      }           } 	}}static BOOLEAN __devinitsisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer){	int i, j, xres, yres, refresh, index;	u32 emodes;	if(buffer[0] != 0x00 || buffer[1] != 0xff ||	   buffer[2] != 0xff || buffer[3] != 0xff ||	   buffer[4] != 0xff || buffer[5] != 0xff ||	   buffer[6] != 0xff || buffer[7] != 0x00) {	   printk(KERN_DEBUG "sisfb: Bad EDID header\n");	   return FALSE;	}	if(buffer[0x12] != 0x01) {	   printk(KERN_INFO "sisfb: EDID version %d not supported\n",	   	buffer[0x12]);	   return FALSE;	}	monitor->feature = buffer[0x18];	if(!buffer[0x14] & 0x80) {	   if(!(buffer[0x14] & 0x08)) {	      printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n");	   }	}	if(buffer[0x13] >= 0x01) {	   /* EDID V1 rev 1 and 2: Search for monitor descriptor	    * to extract ranges	    */	    j = 0x36;	    for(i=0; i<4; i++) {	       if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&	          buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&		  buffer[j + 4] == 0x00) {		  monitor->hmin = buffer[j + 7];		  monitor->hmax = buffer[j + 8];		  monitor->vmin = buffer[j + 5];		  monitor->vmax = buffer[j + 6];		  monitor->dclockmax = buffer[j + 9] * 10 * 1000;		  monitor->datavalid = TRUE;		  break;	       }	       j += 18;	    }	}	if(!monitor->datavalid) {	   /* Otherwise: Get a range from the list of supported	    * Estabished Timings. This is not entirely accurate,	    * because fixed frequency monitors are not supported	    * that way.	    */	   monitor->hmin = 65535; monitor->hmax = 0;	   monitor->vmin = 65535; monitor->vmax = 0;	   monitor->dclockmax = 0;	   emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);	   for(i = 0; i < 13; i++) {	      if(emodes & sisfb_ddcsmodes[i].mask) {	         if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;		 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;		 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;		 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;		 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;	      }	   }	   index = 0x26;	   for(i = 0; i < 8; i++) {	      xres = (buffer[index] + 31) * 8;	      switch(buffer[index + 1] & 0xc0) {	         case 0xc0: yres = (xres * 9) / 16; break;	         case 0x80: yres = (xres * 4) /  5; break;	         case 0x40: yres = (xres * 3) /  4; break;	         default:   yres = xres;	    break;	      }	      refresh = (buffer[index + 1] & 0x3f) + 60;	      if((xres >= 640) && (yres >= 480)) {                 for(j = 0; j < 8; j++) {	            if((xres == sisfb_ddcfmodes[j].x) &&	               (yres == sisfb_ddcfmodes[j].y) &&		       (refresh == sisfb_ddcfmodes[j].v)) {		      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;		      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;		      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;		      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;		      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;	            }	         }	      }	      index += 2;           }	   if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {	      monitor->datavalid = TRUE;	   }	} 	return(monitor->datavalid);}static void __devinit

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -