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

📄 sis_main.c

📁 MIZI Research, Inc.发布的嵌入式Linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * SiS 300/630/540/315H/315 frame buffer device For Kernal 2.4.x * * This driver is partly based on the VBE 2.0 compliant graphic  * boards framebuffer driver, which is  *  * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * *///#undef SISFBDEBUG#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.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/vt_kern.h>#include <linux/capability.h>#include <linux/fs.h>#include <linux/agp_backend.h>#include <linux/types.h>#include <linux/sisfb.h>#include <asm/io.h>#include <asm/mtrr.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#include "osdef.h"#include "vgatypes.h"#include "sis_main.h"/* -------------------- Macro definitions ---------------------------- */#ifdef SISFBDEBUG#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else#define DPRINTK(fmt, args...)#endif#define vgawb(reg,data) \           (outb(data, ivideo.vga_base+reg))#define vgaww(reg,data) \           (outw(data, ivideo.vga_base+reg))#define vgawl(reg,data) \           (outl(data, ivideo.vga_base+reg))#define vgarb(reg)      \           (inb(ivideo.vga_base+reg))/* --------------- Hardware Access Routines -------------------------- */void sisfb_set_reg1 (u16 port, u16 index, u16 data){	outb ((u8) (index & 0xff), port);	port++;	outb ((u8) (data & 0xff), port);}void sisfb_set_reg3 (u16 port, u16 data){	outb ((u8) (data & 0xff), port);}void sisfb_set_reg4 (u16 port, unsigned long data){	outl ((u32) (data & 0xffffffff), port);}u8 sisfb_get_reg1 (u16 port, u16 index){	u8 data;	outb ((u8) (index & 0xff), port);	port += 1;	data = inb (port);	return (data);}u8 sisfb_get_reg2 (u16 port){	u8 data;	data = inb (port);	return (data);}u32 sisfb_get_reg3 (u16 port){	u32 data;	data = inl (port);	return (data);}/* --------------- Interface to BIOS code ---------------------------- */BOOLEAN sisfb_query_VGA_config_space (PSIS_HW_DEVICE_INFO psishw_ext,			      unsigned long offset, unsigned long set,			      unsigned long *value){	static struct pci_dev *pdev = NULL;	static unsigned char init = 0, valid_pdev = 0;	if (!set)		DPRINTK ("Get VGA offset 0x%lx\n", offset);	else		DPRINTK ("Set offset 0x%lx to 0x%lx\n", offset, *value);	if (!init) {		init = TRUE;		pci_for_each_dev (pdev) {			DPRINTK ("Current: 0x%x, target: 0x%x\n", pdev->device,				 ivideo.chip_id);			if ((pdev->vendor == PCI_VENDOR_ID_SI)			    && (pdev->device == ivideo.chip_id)) {				valid_pdev = TRUE;				break;			}		}	}	if (!valid_pdev) {		printk (KERN_DEBUG "Can't find SiS %d VGA device.\n",			ivideo.chip_id);		return FALSE;	}	if (set == 0)		pci_read_config_dword (pdev, offset, (u32 *) value);	else		pci_write_config_dword (pdev, offset, (u32) (*value));	return TRUE;}BOOLEAN sisfb_query_north_bridge_space (PSIS_HW_DEVICE_INFO psishw_ext,				unsigned long offset, unsigned long set,				unsigned long *value){	static struct pci_dev *pdev = NULL;	static unsigned char init = 0, valid_pdev = 0;	u16 nbridge_id = 0;	if (!init) {		init = TRUE;		switch (ivideo.chip) {		case SIS_540:			nbridge_id = PCI_DEVICE_ID_SI_540;			break;		case SIS_630:			nbridge_id = PCI_DEVICE_ID_SI_630;			break;		case SIS_730:			nbridge_id = PCI_DEVICE_ID_SI_730;			break;		case SIS_550:			nbridge_id = PCI_DEVICE_ID_SI_550;			break;		default:			nbridge_id = 0;			break;		}		pci_for_each_dev (pdev) {			DPRINTK ("Current: 0x%x, target: 0x%x\n", pdev->device,				 ivideo.chip_id);			if ((pdev->vendor == PCI_VENDOR_ID_SI)			    && (pdev->device == nbridge_id)) {				valid_pdev = TRUE;				break;			}		}	}	if (!valid_pdev) {		printk (KERN_DEBUG "Can't find SiS %d North Bridge device.\n",			nbridge_id);		return FALSE;	}	if (set == 0)		pci_read_config_dword (pdev, offset, (u32 *) value);	else		pci_write_config_dword (pdev, offset, (u32) (*value));	return TRUE;}/* -------------------- Export functions ----------------------------- */static void sis_get_glyph (SIS_GLYINFO * gly){	struct display *p = &fb_display[currcon];	u16 c;	u8 *cdat;	int widthb;	u8 *gbuf = gly->gmask;	int size;	gly->fontheight = fontheight (p);	gly->fontwidth = fontwidth (p);	widthb = (fontwidth (p) + 7) / 8;	c = gly->ch & p->charmask;	if (fontwidth (p) <= 8)		cdat = p->fontdata + c * fontheight (p);	else		cdat = p->fontdata + (c * fontheight (p) << 1);	size = fontheight (p) * widthb;	memcpy (gbuf, cdat, size);	gly->ngmask = size;}void sis_dispinfo (struct ap_data *rec){	rec->minfo.bpp = ivideo.video_bpp;	rec->minfo.xres = ivideo.video_width;	rec->minfo.yres = ivideo.video_height;	rec->minfo.v_xres = ivideo.video_vwidth;	rec->minfo.v_yres = ivideo.video_vheight;	rec->minfo.org_x = ivideo.org_x;	rec->minfo.org_y = ivideo.org_y;	rec->minfo.vrate = ivideo.refresh_rate;	rec->iobase = ivideo.vga_base - 0x30;	rec->mem_size = ivideo.video_size;	rec->disp_state = ivideo.disp_state;	rec->version = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL;	rec->hasVB = ivideo.hasVB;	rec->TV_type = ivideo.TV_type;	rec->TV_plug = ivideo.TV_plug;	rec->chip = ivideo.chip;}/* ------------------ Internal Routines ------------------------------ */static void sisfb_search_mode (const char *name){	int i = 0;	if (name == NULL)		return;	while (sisbios_mode[i].mode_no != 0) {		if (!strcmp (name, sisbios_mode[i].name)) {			sisfb_mode_idx = i;			break;		}		i++;	}	if (sisfb_mode_idx < 0)		DPRINTK ("Invalid user mode : %s\n", name);}static void sisfb_validate_mode (void){	switch (ivideo.disp_state & DISPTYPE_DISP2) {	case DISPTYPE_LCD:// Eden Chen		switch (sishw_ext.ulCRT2LCDType) {		case LCD_1024x768:			if (sisbios_mode[sisfb_mode_idx].xres > 1024)				sisfb_mode_idx = -1;			break;		case LCD_1280x1024:		case LCD_1280x960:			if (sisbios_mode[sisfb_mode_idx].xres > 1280)				sisfb_mode_idx = -1;			break;		case LCD_2048x1536:			if (sisbios_mode[sisfb_mode_idx].xres > 2048)				sisfb_mode_idx = -1;			break;		case LCD_1920x1440:			if (sisbios_mode[sisfb_mode_idx].xres > 1920)				sisfb_mode_idx = -1;			break;		case LCD_1600x1200:			if (sisbios_mode[sisfb_mode_idx].xres > 1600)				sisfb_mode_idx = -1;			break;		case LCD_800x600:			if (sisbios_mode[sisfb_mode_idx].xres > 800)				sisfb_mode_idx = -1;			break;		case LCD_640x480:			if (sisbios_mode[sisfb_mode_idx].xres > 640)				sisfb_mode_idx = -1;			break;		default:			sisfb_mode_idx = -1;		}// ~Eden Chen		if (sisbios_mode[sisfb_mode_idx].xres == 720)			sisfb_mode_idx = -1;		break;	case DISPTYPE_TV:		switch (sisbios_mode[sisfb_mode_idx].xres) {		case 800:		case 640:			break;		case 720:			if (ivideo.TV_type == TVMODE_NTSC) {				if (sisbios_mode[sisfb_mode_idx].yres != 480)					sisfb_mode_idx = -1;			} else if (ivideo.TV_type == TVMODE_PAL) {				if (sisbios_mode[sisfb_mode_idx].yres != 576)					sisfb_mode_idx = -1;			}			break;			/*karl */		case 1024:			if (ivideo.TV_type == TVMODE_NTSC) {				if (sisbios_mode[sisfb_mode_idx].bpp == 32)					sisfb_mode_idx -= 1;			}			break;		default:			sisfb_mode_idx = -1;		}		break;	}}static u8 sisfb_search_refresh_rate (unsigned int rate){	u16 xres, yres;	int i = 0;	xres = sisbios_mode[sisfb_mode_idx].xres;	yres = sisbios_mode[sisfb_mode_idx].yres;	sisfb_rate_idx = 0;	while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {		if ((sisfb_vrate[i].xres == xres)		    && (sisfb_vrate[i].yres == yres)) {			if (sisfb_vrate[i].refresh == rate) {				sisfb_rate_idx = sisfb_vrate[i].idx;				break;			} else if (sisfb_vrate[i].refresh > rate) {				if ((sisfb_vrate[i].refresh - rate) <= 2) {					DPRINTK					    ("Adjust rate from %d up to %d\n",					     rate, sisfb_vrate[i].refresh);					sisfb_rate_idx = sisfb_vrate[i].idx;					ivideo.refresh_rate =					    sisfb_vrate[i].refresh;				} else if (((rate - sisfb_vrate[i - 1].refresh) <=  2) 				    	&& (sisfb_vrate[i].idx != 1)) {					DPRINTK("Adjust rate from %d down to %d\n",					     rate, sisfb_vrate[i - 1].refresh);					sisfb_rate_idx = sisfb_vrate[i - 1].idx;					ivideo.refresh_rate = sisfb_vrate[i - 1].refresh;				}				break;			}		}		i++;	}	if (sisfb_rate_idx > 0) {		return sisfb_rate_idx;	} else {		DPRINTK ("Unsupported rate %d for %dx%d mode\n", rate, xres,			 yres);		return 0;	}}static int sis_getcolreg (unsigned regno, unsigned *red, unsigned *green, unsigned *blue,	       unsigned *transp, struct fb_info *fb_info){	if (regno >= video_cmap_len)		return 1;	*red = palette[regno].red;	*green = palette[regno].green;	*blue = palette[regno].blue;	*transp = 0;	return 0;}static int sis_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue,	       unsigned transp, struct fb_info *fb_info){	if (regno >= video_cmap_len)		return 1;	palette[regno].red = red;	palette[regno].green = green;	palette[regno].blue = blue;	switch (ivideo.video_bpp) {#ifdef FBCON_HAS_CFB8	case 8:		vgawb (DAC_ADR, regno);		vgawb (DAC_DATA, red >> 10);		vgawb (DAC_DATA, green >> 10);		vgawb (DAC_DATA, blue >> 10);		if (ivideo.disp_state & DISPTYPE_DISP2) {			vgawb (DAC2_ADR, regno);			vgawb (DAC2_DATA, red >> 8);			vgawb (DAC2_DATA, green >> 8);			vgawb (DAC2_DATA, blue >> 8);		}		break;#endif#ifdef FBCON_HAS_CFB16	case 15:	case 16:		fbcon_cmap.cfb16[regno] =		    ((red & 0xf800)) |		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);		break;#endif#ifdef FBCON_HAS_CFB24	case 24:		red >>= 8;		green >>= 8;		blue >>= 8;		fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue);		break;#endif#ifdef FBCON_HAS_CFB32	case 32:		red >>= 8;		green >>= 8;		blue >>= 8;		fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);		break;#endif	}	return 0;}static int sisfb_do_set_var (struct fb_var_screeninfo *var, int isactive,		  struct fb_info *info){	unsigned int htotal =	    var->left_margin + var->xres + var->right_margin + var->hsync_len;	unsigned int vtotal =	    var->upper_margin + var->yres + var->lower_margin + var->vsync_len;	double drate = 0, hrate = 0;	int found_mode = 0;	int old_mode;	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)		vtotal <<= 1;	else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)		vtotal <<= 2;	else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)		var->yres <<= 1;	if (!htotal || !vtotal) {		DPRINTK ("Invalid 'var' Information!\n");		return -EINVAL;	}	drate = 1E12 / var->pixclock;	hrate = drate / htotal;	ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);	DPRINTK ("Chagne mode to %dx%dx%d-%dMHz\n",		 var->xres, var->yres, var->bits_per_pixel,		 ivideo.refresh_rate);	old_mode = sisfb_mode_idx;	sisfb_mode_idx = 0;	while ((sisbios_mode[sisfb_mode_idx].mode_no != 0)	       && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) {		if ((sisbios_mode[sisfb_mode_idx].xres == var->xres)		    && (sisbios_mode[sisfb_mode_idx].yres == var->yres)		    && (sisbios_mode[sisfb_mode_idx].bpp ==			var->bits_per_pixel)) {			sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;			found_mode = 1;			break;		}		sisfb_mode_idx++;	}	if (found_mode)		sisfb_validate_mode ();	else		sisfb_mode_idx = -1;	if (sisfb_mode_idx < 0) {		DPRINTK ("sisfb does not support mode %dx%d-%d\n", var->xres,			 var->yres, var->bits_per_pixel);		sisfb_mode_idx = old_mode;		return -EINVAL;	}	if (sisfb_search_refresh_rate (ivideo.refresh_rate) == 0) {		sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;		ivideo.refresh_rate = 60;	}	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {		sisfb_pre_setmode ();// Eden Chen/*#ifdef CONFIG_FB_SIS_300		if (SiSSetMode(&sishw_ext, sisfb_mode_no)) {			DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no);			return -1;		}#endif#ifdef CONFIG_FB_SIS_315		if (SiSSetMode310(&sishw_ext, sisfb_mode_no)) {			DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no);			return -1;		}#endif*/		if (SiSSetMode (&sishw_ext, sisfb_mode_no) == 0) {			DPRINTK ("set mode[0x%x]: failed\n", sisfb_mode_no);			return -1;		}		vgawb (SEQ_ADR, IND_SIS_PASSWORD);		vgawb (SEQ_DATA, SIS_PASSWORD);// ~Eden Chen		sisfb_post_setmode ();		DPRINTK ("Set New Mode : %dx%dx%d-%d \n",			 sisbios_mode[sisfb_mode_idx].xres,			 sisbios_mode[sisfb_mode_idx].yres,			 sisbios_mode[sisfb_mode_idx].bpp, ivideo.refresh_rate);		ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;		ivideo.video_vwidth = ivideo.video_width =

⌨️ 快捷键说明

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