sis_main.c

来自「讲述linux的初始化过程」· C语言 代码 · 共 2,375 行 · 第 1/4 页

C
2,375
字号
/* * SiS 300/630/540 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> * */#define EXPORT_SYMTAB#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/malloc.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/sisfb.h>#include <linux/fs.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 "sis.h"#ifdef NOBIOS#include "bios.h"#endif/* ------------------- Constant Definitions ------------------------- *//* capabilities */#define TURBO_QUEUE_CAP      0x80#define HW_CURSOR_CAP        0x40/* VGA register Offsets */#define SEQ_ADR                   (0x14)#define SEQ_DATA                  (0x15)#define DAC_ADR                   (0x18)#define DAC_DATA                  (0x19)#define CRTC_ADR                  (0x24)#define CRTC_DATA                 (0x25)#define DAC2_ADR                   0x16 - 0x30#define DAC2_DATA                  0x17 - 0x30/* SiS indexed register indexes */#define IND_SIS_PASSWORD          (0x05)#define IND_SIS_DRAM_SIZE         (0x14)#define IND_SIS_MODULE_ENABLE     (0x1E)#define IND_SIS_PCI_ADDRESS_SET   (0x20)#define IND_SIS_TURBOQUEUE_ADR    (0x26)#define IND_SIS_TURBOQUEUE_SET    (0x27)/* Sis register value */#define SIS_PASSWORD              (0x86)#define SIS_2D_ENABLE             (0x40)#define SIS_MEM_MAP_IO_ENABLE     (0x01)#define SIS_PCI_ADDR_ENABLE       (0x80)//#define MMIO_SIZE                 0x10000	/* 64K MMIO capability */#define MAX_ROM_SCAN              0x10000#define RESERVED_MEM_SIZE_4M      0x400000	/* 4M */#define RESERVED_MEM_SIZE_8M      0x800000	/* 8M *//* Mode set stuff */#define DEFAULT_MODE         0	/* 640x480x8 */#define DEFAULT_LCDMODE      9	/* 800x600x8 */#define DEFAULT_TVMODE       9	/* 800x600x8 *//* heap stuff */#define OH_ALLOC_SIZE         4000#define SENTINEL              0x7fffffff#define TURBO_QUEUE_AREA_SIZE 0x80000	/* 512K */#define HW_CURSOR_AREA_SIZE   0x1000	/* 4K *//* ------------------- Global Variables ----------------------------- */struct video_info ivideo;HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0};struct GlyInfo {	unsigned char ch;	int fontwidth;	int fontheight;	u8 gmask[72];	int ngmask;};/* Supported SiS Chips list */static struct board {	u16 vendor, device;	const char *name;} dev_list[] = {	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     "SIS 300"},	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"},	{0, 0, NULL}};/* card parameters */unsigned long rom_base;unsigned long rom_vbase;/* mode */static int video_type = FB_TYPE_PACKED_PIXELS;static int video_linelength;static int video_cmap_len;static int sisfb_off = 0;static int crt1off = 0;static struct fb_var_screeninfo default_var = {	0, 0, 0, 0,	0, 0,	0,	0,	{0, 8, 0},	{0, 8, 0},	{0, 8, 0},	{0, 0, 0},	0,	FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,	0,	FB_VMODE_NONINTERLACED,	{0, 0, 0, 0, 0, 0}};static struct display disp;static struct fb_info fb_info;static struct {	u16 blue, green, red, pad;} palette[256];static union {#ifdef FBCON_HAS_CFB16	u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB24	u32 cfb24[16];#endif#ifdef FBCON_HAS_CFB32	u32 cfb32[16];#endif} fbcon_cmap;static int inverse = 0;static int currcon = 0;static struct display_switch sisfb_sw;static u8 caps = 0;static unsigned long MMIO_SIZE = 0;/* ModeSet stuff */unsigned char  uDispType = 0;int mode_idx = -1;u8 mode_no = 0;u8 rate_idx = 0;static const struct _sisbios_mode {	char name[15];	u8 mode_no;	u16 xres;	u16 yres;	u16 bpp;	u16 rate_idx;	u16 cols;	u16 rows;} sisbios_mode[] = {	{"640x480x8",    0x2E,  640,  480,  8, 1,  80, 30},	{"640x480x16",   0x44,  640,  480, 16, 1,  80, 30},	{"640x480x32",   0x62,  640,  480, 32, 1,  80, 30},	{"720x480x8",    0x31,  720,  480,  8, 1,  90, 30}, 	/* NTSC TV */	{"720x480x16",   0x33,  720,  480, 16, 1,  90, 30}, 	{"720x480x32",   0x35,  720,  480, 32, 1,  90, 30}, 	{"720x576x8",    0x32,  720,  576,  8, 1,  90, 36}, 	/* PAL TV */	{"720x576x16",   0x34,  720,  576, 16, 1,  90, 36}, 	{"720x576x32",   0x36,  720,  576, 32, 1,  90, 36}, 	{"800x600x8",    0x30,  800,  600,  8, 2, 100, 37},	{"800x600x16",   0x47,  800,  600, 16, 2, 100, 37},	{"800x600x32",   0x63,  800,  600, 32, 2, 100, 37}, 	{"1024x768x8",   0x38, 1024,  768,  8, 2, 128, 48},	{"1024x768x16",  0x4A, 1024,  768, 16, 2, 128, 48},	{"1024x768x32",  0x64, 1024,  768, 32, 2, 128, 48},	{"1280x1024x8",  0x3A, 1280, 1024,  8, 2, 160, 64},	{"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},	{"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},	{"1600x1200x8",  0x3C, 1600, 1200,  8, 1, 200, 75},	{"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},	{"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},	{"1920x1440x8",  0x68, 1920, 1440,  8, 1, 240, 75},	{"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},	{"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},	{"\0", 0x00, 0, 0, 0, 0, 0, 0}};static struct _vrate {	u16 idx;	u16 xres;	u16 yres;	u16 refresh;} vrate[] = {	{1,  640,  480,  60}, {2,  640, 480,  72}, {3,  640, 480,  75}, {4,  640, 480,  85},	{5,  640,  480, 100}, {6,  640, 480, 120}, {7,  640, 480, 160}, {8,  640, 480, 200},	{1,  720,  480,  60},	{1,  720,  576,  50},	{1,  800,  600,  56}, {2,  800, 600,  60}, {3,  800, 600,  72}, {4,  800, 600,  75},	{5,  800,  600,  85}, {6,  800, 600, 100}, {7,  800, 600, 120}, {8,  800, 600, 160},	{1, 1024,  768,  43}, {2, 1024, 768,  60}, {3, 1024, 768,  70}, {4, 1024, 768,  75},	{5, 1024,  768,  85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},	{1, 1280, 1024,  43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},	{1, 1600, 1200,  60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},	{5, 1600, 1200,  85},	{1, 1920, 1440,  60},	{0, 0, 0, 0}};/* HEAP stuff */struct OH {	struct OH *pohNext;	struct OH *pohPrev;	unsigned long ulOffset;	unsigned long ulSize;};struct OHALLOC {	struct OHALLOC *pohaNext;	struct OH aoh[1];};struct HEAP {	struct OH ohFree;	struct OH ohUsed;	struct OH *pohFreeList;	struct OHALLOC *pohaChain;	unsigned long ulMaxFreeSize;};struct HEAP heap;unsigned long heap_start;unsigned long heap_end;unsigned long heap_size;unsigned int tqueue_pos;unsigned long hwcursor_vbase;/* -------------------- 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))/* ---------------------- Routine Prototype ------------------------- *//* Interface used by the world */int sisfb_setup(char *options);static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,			 struct fb_info *info);static int sisfb_get_var(struct fb_var_screeninfo *var, int con,			 struct fb_info *info);static int sisfb_set_var(struct fb_var_screeninfo *var, int con,			 struct fb_info *info);static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,			  struct fb_info *info);static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,			  struct fb_info *info);static int sisfb_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg, int con,		       struct fb_info *info);/* Interface to the low level console driver */int sisfb_init(void);static int sisfb_update_var(int con, struct fb_info *info);static int sisfb_switch(int con, struct fb_info *info);static void sisfb_blank(int blank, struct fb_info *info);/* Internal routines */static void crtc_to_var(struct fb_var_screeninfo *var);static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,			 unsigned *blue, unsigned *transp,			 struct fb_info *fb_info);static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,			 unsigned blue, unsigned transp,			 struct fb_info *fb_info);static void do_install_cmap(int con, struct fb_info *info);static int do_set_var(struct fb_var_screeninfo *var, int isactive,		      struct fb_info *info);/* set-mode routines */void SetReg1(u16 port, u16 index, u16 data);void SetReg3(u16 port, u16 data);void SetReg4(u16 port, unsigned long data);u8 GetReg1(u16 port, u16 index);u8 GetReg2(u16 port);u32 GetReg3(u16 port);extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,				USHORT ModeNo);extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);static void pre_setmode(void);static void post_setmode(void);static void search_mode(const char *name);static u8 search_refresh_rate(unsigned int rate);/* heap routines */static int sisfb_heap_init(void);static struct OH *poh_new_node(void);static struct OH *poh_allocate(unsigned long size);static struct OH *poh_free(unsigned long base);static void delete_node(struct OH *poh);static void insert_node(struct OH *pohList, struct OH *poh);static void free_node(struct OH *poh);/* ---------------------- Internal Routines ------------------------- */inline static u32 RD32(unsigned char *base, s32 off){	return readl(base + off);}inline static void WR32(unsigned char *base, s32 off, u32 v){	writel(v, base + off);}inline static void WR16(unsigned char *base, s32 off, u16 v){	writew(v, base + off);}inline static void WR8(unsigned char *base, s32 off, u8 v){	writeb(v, base + off);}inline static u32 regrl(s32 off){	return RD32(ivideo.mmio_vbase, off);}inline static void regwl(s32 off, u32 v){	WR32(ivideo.mmio_vbase, off, v);}inline static void regww(s32 off, u16 v){	WR16(ivideo.mmio_vbase, off, v);}inline static void regwb(s32 off, u8 v){	WR8(ivideo.mmio_vbase, off, v);}/*  *    Get CRTC registers to set var  */static void crtc_to_var(struct fb_var_screeninfo *var){	u16 VRE, VBE, VRS, VBS, VDE, VT;	u16 HRE, HBE, HRS, HBS, HDE, HT;	u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;	int A, B, C, D, E, F, temp;	double hrate, drate;	vgawb(SEQ_ADR, 0x6);	uSRdata = vgarb(SEQ_DATA);	if (uSRdata & 0x20)		var->vmode = FB_VMODE_INTERLACED;	else		var->vmode = FB_VMODE_NONINTERLACED;	switch ((uSRdata & 0x1c) >> 2) {	case 0:		var->bits_per_pixel = 8;		break;	case 2:		var->bits_per_pixel = 16;		break;	case 4:		var->bits_per_pixel = 32;		break;	}	switch (var->bits_per_pixel) {	case 8:		var->red.length = 6;		var->green.length = 6;		var->blue.length = 6;		video_cmap_len = 256;		break;	case 16:		/* RGB 565 */		var->red.offset = 11;		var->red.length = 5;		var->green.offset = 5;		var->green.length = 6;		var->blue.offset = 0;		var->blue.length = 5;		var->transp.offset = 0;		var->transp.length = 0;		video_cmap_len = 16;		break;	case 24:		/* RGB 888 */		var->red.offset = 16;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 0;		video_cmap_len = 16;		break;	case 32:		var->red.offset = 16;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;		var->transp.offset = 24;		var->transp.length = 8;		video_cmap_len = 16;		break;	}	vgawb(SEQ_ADR, 0xa);	uSRdata = vgarb(SEQ_DATA);	vgawb(CRTC_ADR, 0x6);	uCRdata = vgarb(CRTC_DATA);	vgawb(CRTC_ADR, 0x7);	uCRdata2 = vgarb(CRTC_DATA);	VT =	    (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |	    ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<					      10);	A = VT + 2;	vgawb(CRTC_ADR, 0x12);	uCRdata = vgarb(CRTC_DATA);	VDE =	    (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |	    ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);	E = VDE + 1;	vgawb(CRTC_ADR, 0x10);	uCRdata = vgarb(CRTC_DATA);	VRS =	    (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |	    ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);	F = VRS + 1 - E;	vgawb(CRTC_ADR, 0x15);	uCRdata = vgarb(CRTC_DATA);	vgawb(CRTC_ADR, 0x9);	uCRdata3 = vgarb(CRTC_DATA);	VBS =	    (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |	    ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);	vgawb(CRTC_ADR, 0x16);	uCRdata = vgarb(CRTC_DATA);	VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);	temp = VBE - ((E - 1) & 511);	B = (temp > 0) ? temp : (temp + 512);	vgawb(CRTC_ADR, 0x11);	uCRdata = vgarb(CRTC_DATA);	VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);	temp = VRE - ((E + F - 1) & 31);	C = (temp > 0) ? temp : (temp + 32);	D = B - F - C;	var->yres = var->yres_virtual = E;	var->upper_margin = D;	var->lower_margin = F;	var->vsync_len = C;	vgawb(SEQ_ADR, 0xb);	uSRdata = vgarb(SEQ_DATA);	vgawb(CRTC_ADR, 0x0);	uCRdata = vgarb(CRTC_DATA);	HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);	A = HT + 5;	vgawb(CRTC_ADR, 0x1);	uCRdata = vgarb(CRTC_DATA);	HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);	E = HDE + 1;	vgawb(CRTC_ADR, 0x4);	uCRdata = vgarb(CRTC_DATA);	HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);	F = HRS - E - 3;	vgawb(CRTC_ADR, 0x2);	uCRdata = vgarb(CRTC_DATA);	HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);	vgawb(SEQ_ADR, 0xc);	uSRdata = vgarb(SEQ_DATA);	vgawb(CRTC_ADR, 0x3);	uCRdata = vgarb(CRTC_DATA);	vgawb(CRTC_ADR, 0x5);	uCRdata2 = vgarb(CRTC_DATA);	HBE =	    (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |	    ((u16) (uSRdata & 0x03) << 6);	HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);	temp = HBE - ((E - 1) & 255);	B = (temp > 0) ? temp : (temp + 256);	temp = HRE - ((E + F + 3) & 63);	C = (temp > 0) ? temp : (temp + 64);	D = B - F - C;	var->xres = var->xres_virtual = E * 8;	var->left_margin = D * 8;	var->right_margin = F * 8;	var->hsync_len = C * 8;	var->activate = FB_ACTIVATE_NOW;	var->sync = 0;	uMRdata = vgarb(0x1C);	if (uMRdata & 0x80)		var->sync &= ~FB_SYNC_VERT_HIGH_ACT;	else		var->sync |= FB_SYNC_VERT_HIGH_ACT;	if (uMRdata & 0x40)		var->sync &= ~FB_SYNC_HOR_HIGH_ACT;	else		var->sync |= FB_SYNC_HOR_HIGH_ACT;	VT += 2;	VT <<= 1;	HT = (HT + 5) * 8;	hrate = (double) ivideo.refresh_rate * (double) VT / 2;	drate = hrate * HT;	var->pixclock = (u32) (1E12 / drate);}static void sisfb_set_disp(int con, struct fb_var_screeninfo *var){	struct fb_fix_screeninfo fix;

⌨️ 快捷键说明

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