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

📄 sis_main.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * SiS 300/540/630[S]/730[S], * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX], * XGI V3XT/V5/V8, Z7 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 * * Copyright (C) 2001-2005 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/smp_lock.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/fb.h>#include <linux/selection.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#include <linux/vt_kern.h>#endif#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#endifstatic void sisfb_handle_command(struct sis_video_info *ivideo,				 struct sisfb_cmd *sisfb_command);/* ------------------ 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_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}/* ------------- Parameter parsing -------------- */static void __devinitsisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet){	int i = 0, j = 0;	/* 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 void __devinitsisfb_search_mode(char *name, BOOLEAN quiet){	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;	int i = 0;	char strbuf[16], strbuf1[20];	char *nameptr = name;	/* 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;	/* 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;	/* 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;	/* 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++;			}		}	}}/* ----------- Various detection routines ----------- */static void __devinitsisfb_detect_custom_timing(struct sis_video_info *ivideo){	unsigned char *biosver = NULL;	unsigned char *biosdate = NULL;	BOOLEAN footprint;	u32 chksum = 0;	int i, j;	if(ivideo->SiS_Pr.UseROM) {		biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;		biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;		for(i = 0; i < 32768; i++)			chksum += ivideo->SiS_Pr.VirtualRomBase[i];	}	i = 0;	do {		if( (mycustomttable[i].chipID == ivideo->chip)			&&		    ((!strlen(mycustomttable[i].biosversion)) ||		     (ivideo->SiS_Pr.UseROM &&		      (!strncmp(mycustomttable[i].biosversion, biosver,				strlen(mycustomttable[i].biosversion)))))	&&		    ((!strlen(mycustomttable[i].biosdate)) ||		     (ivideo->SiS_Pr.UseROM &&		      (!strncmp(mycustomttable[i].biosdate, biosdate,				strlen(mycustomttable[i].biosdate)))))		&&		    ((!mycustomttable[i].bioschksum) ||		     (ivideo->SiS_Pr.UseROM &&		      (mycustomttable[i].bioschksum == chksum)))		&&		    (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&		    (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {			footprint = TRUE;			for(j = 0; j < 5; j++) {				if(mycustomttable[i].biosFootprintAddr[j]) {					if(ivideo->SiS_Pr.UseROM) {						if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=							mycustomttable[i].biosFootprintData[j]) {							footprint = FALSE;						}					} else						footprint = FALSE;				}			}			if(footprint) {				ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;				printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",					mycustomttable[i].vendorName,				mycustomttable[i].cardName);				printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",					mycustomttable[i].optionName);				break;			}		}		i++;	} while(mycustomttable[i].chipID);}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	    */

⌨️ 快捷键说明

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