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

📄 sis_main.c

📁 linux下的VIDEO接口驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * SiS 300/630/730/540/315/550/650/740 frame buffer device * for Linux kernels 2.4.x and 2.5.x * * Partly based on the VBE 2.0 compliant graphic boards framebuffer driver, * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * Authors:   	SiS (www.sis.com.tw) *		(Various others) *		Thomas Winischhofer <thomas@winischhofer.net>: *			- many fixes and enhancements for 630 & 310 series, *			- extended bridge handling, TV output for Chrontel *			- memory queue handling enhancements, *			- everything marked with "TW" *			(see http://www.winischhofer.net/linuxsis630.shtml *			for more information and updates) */#include <linux/config.h>#include <linux/version.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"//#ifdef LINUXBIOS//#include "bios.h"//#endif/* -------------------- Macro definitions ---------------------------- */// #define SISFBDEBUG#undef SISFBDEBUG /* TW */#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);}// Eden Chen//void sisfb_clear_DAC(u16 port)//{//	int i,j;////	vgawb(DAC_ADR, 0x00);//	for(i=0; i<256; i++)//		for(j=0; j<3; j++)//			vgawb(DAC_DATA, 0);//}//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext)//{//	memset((char *) ivideo.video_vbase, 0,//		video_linelength * ivideo.video_height);//}// ~Eden Chen/* --------------- Interface to BIOS code ---------------------------- */BOOLEANsisfb_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("sisfb: Get VGA offset 0x%lx\n", offset);	else		DPRINTK("sisfb: Set offset 0x%lx to 0x%lx\n", offset, *value);	if (!init) {		init = TRUE;		pci_for_each_dev(pdev) {			DPRINTK("sisfb: 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 "sisfb: 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;		case SIS_650:			nbridge_id = PCI_DEVICE_ID_SI_650;			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 "sisfb: 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)		printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);}static void sisfb_validate_mode(void){	switch (ivideo.disp_state & DISPTYPE_DISP2) {	case DISPTYPE_LCD:	    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;		case LCD_320x480:	/* TW: FSTN */			if (sisbios_mode[sisfb_mode_idx].xres > 320)				sisfb_mode_idx = -1;			break;		default:			sisfb_mode_idx = -1;		}		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;			}			/* TW: LVDS/CHRONTEL only supports 640 and 800 */			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||						ivideo.hasVB == HASVB_CHRONTEL)					sisfb_mode_idx = -1;			break;		case 1024:			if (ivideo.TV_type == TVMODE_NTSC) {				if(sisbios_mode[sisfb_mode_idx].bpp == 32)				       sisfb_mode_idx = -1; /* TW; was -= 1 */				       /* TW: Should this mean a switch-back to				        *     16bpp or simply 'illegal mode'?					*/			}			/* TW: LVDS/CHRONTEL only supports 640 and 800 */			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||						ivideo.hasVB == HASVB_CHRONTEL)					sisfb_mode_idx = -1;			break;		default:			sisfb_mode_idx = -1;		}		break;	}}static void sisfb_search_crt2type(const char *name){	int i = 0;	if (name == NULL)		return;	while (sis_crt2type[i].type_no != -1) {		if (!strcmp(name, sis_crt2type[i].name)) {			sisfb_crt2type = sis_crt2type[i].type_no;			break;		}		i++;	}	if (sisfb_crt2type < 0)		printk(KERN_INFO "sisfb: Invalid CRT2 type: %s\n", name);}static void sisfb_search_queuemode(const char *name){	int i = 0;	if (name == NULL)		return;	while (sis_queuemode[i].type_no != -1) {		if (!strcmp(name, sis_queuemode[i].name)) {			sisfb_queuemode = sis_queuemode[i].type_no;			break;		}		i++;	}	if (sisfb_queuemode < 0)		printk(KERN_INFO "sisfb: Invalid queuemode type: %s\n", name);}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("sisfb: Adjusting 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("sisfb: Adjusting 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 {		printk(KERN_INFO			"sisfb: Unsupported rate %d for %dx%d\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;

⌨️ 快捷键说明

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