📄 sis_main.c
字号:
/* * SiS 300/630/730/540/315/550/650/740 frame buffer device * for Linux kernels 2.4.x and 2.5.x * * Authors: SiS (www.sis.com.tw) * Thomas Winischhofer <thomas@winischhofer.net>: * - SiS Xabre (330) support * - many fixes and enhancements for all chipset series, * - extended bridge handling, TV output for Chrontel 7005 * - 650/740/LVDS support (for LCD panels up to 1600x1200) * - 650/740/Chrontel 7019 support (LCD and TV) * - 30xB/30xLV LCD, TV and VGA2 support * - memory queue handling enhancements, * - 2D acceleration and y-panning, * - rewritten for 2.5 API (>= 2.5.63) * - etc. * (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>#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 <asm/uaccess.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#include <linux/spinlock.h>#endif#include "osdef.h"#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#include <video/sisfb.h>#else#include <linux/sisfb.h>#endif#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 "vgatypes.h"#include "sis_main.h"#include "sis.h"#if 0#ifdef LINUXBIOS#include "bios.h"#endif#endif/* -------------------- Macro definitions ---------------------------- */#undef SISFBDEBUG /* TW: no debugging */#ifdef SISFBDEBUG#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else#define DPRINTK(fmt, args...)#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#ifdef SISFBACCEL#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#endif/* --------------- Hardware Access Routines -------------------------- */void sisfb_set_reg4(u16 port, unsigned long data){ outl((u32) (data & 0xffffffff), port);}u32 sisfb_get_reg3(u16 port){ u32 data; data = inl(port); return (data);}/* ------------ Interface for init & mode switching 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; case SIS_740: nbridge_id = PCI_DEVICE_ID_SI_740; 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;}/* ------------------ Internal helper routines ----------------- */static void sisfb_search_mode(const char *name){ int i = 0, j = 0; if(name == NULL) { 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 (!strcmp(name, sisbios_mode[MODE_INDEX_NONE].name)) { printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n"); sisfb_mode_idx = DEFAULT_MODE; return; }#endif while(sisbios_mode[i].mode_no != 0) { if (!strcmp(name, sisbios_mode[i].name)) { sisfb_mode_idx = i; j = 1; break; } i++; } if(!j) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", name);}static void sisfb_search_vesamode(unsigned int vesamode){ int i = 0, j = 0; if(vesamode == 0) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) sisfb_mode_idx = MODE_INDEX_NONE;#else printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. 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) { if( (sisbios_mode[i].vesa_mode_no_1 == vesamode) || (sisbios_mode[i].vesa_mode_no_2 == vesamode) ) { sisfb_mode_idx = i; j = 1; break; } i++; } if(!j) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);}static int sisfb_validate_mode(int myindex, unsigned long vbflags){ u16 xres, yres;#ifdef CONFIG_FB_SIS_300 if(sisvga_engine == SIS_300_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS300)) { return(-1); } }#endif#ifdef CONFIG_FB_SIS_315 if(sisvga_engine == SIS_315_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS315)) { return(-1); } }#endif switch (vbflags & VB_DISPTYPE_DISP2) { case CRT2_LCD: switch (sishw_ext.ulCRT2LCDType) { case LCD_640x480: xres = 640; yres = 480; break; case LCD_800x600: xres = 800; yres = 600; break; case LCD_1024x600: xres = 1024; yres = 600; break; case LCD_1024x768: xres = 1024; yres = 768; break; case LCD_1152x768: xres = 1152; yres = 768; break; case LCD_1280x960: xres = 1280; yres = 960; break; case LCD_1280x768: xres = 1280; yres = 768; break; case LCD_1280x1024: xres = 1280; yres = 1024; break; case LCD_1400x1050: xres = 1400; yres = 1050; break; case LCD_1600x1200: xres = 1600; yres = 1200; break; case LCD_320x480: /* TW: FSTN */ xres = 320; yres = 480; break; default: xres = 0; yres = 0; break; } if(sisbios_mode[myindex].xres > xres) { return(-1); } if(sisbios_mode[myindex].yres > yres) { return(-1); } if(vbflags & (VB_LVDS | VB_30xBDH)) { switch (sisbios_mode[myindex].xres) { case 320: if((sisbios_mode[myindex].yres != 200) && (sisbios_mode[myindex].yres != 240) && (sisbios_mode[myindex].yres != 480)) return -1; if(sisbios_mode[myindex].yres == 480) { if(!enable_dstn) return -1; } break; case 400: if(sisbios_mode[myindex].yres != 300) return -1; break; case 512: if(sisbios_mode[myindex].yres != 384) return -1; if(sishw_ext.ulCRT2LCDType == LCD_1024x600) return -1; break; case 640: if((sisbios_mode[myindex].yres != 400) && (sisbios_mode[myindex].yres != 480)) return -1; break; case 800: if(sisbios_mode[myindex].yres != 600) return -1; break; case 1024: if((sisbios_mode[myindex].yres != 600) && (sisbios_mode[myindex].yres != 768)) return -1; if((sisbios_mode[myindex].yres == 600) && (sishw_ext.ulCRT2LCDType != LCD_1024x600)) return -1; break; case 1152: if((sisbios_mode[myindex].yres) != 768) return -1; if(sishw_ext.ulCRT2LCDType != LCD_1152x768) return -1; break; case 1280: if((sisbios_mode[myindex].yres != 768) && (sisbios_mode[myindex].yres != 1024)) return -1; if((sisbios_mode[myindex].yres == 768) && (sishw_ext.ulCRT2LCDType != LCD_1280x768)) return -1; break; case 1400: if(sisbios_mode[myindex].yres != 1050) return -1; break; case 1600: if(sisbios_mode[myindex].yres != 1200) return -1; break; default: return -1; } } else { switch (sisbios_mode[myindex].xres) { case 320: if((sisbios_mode[myindex].yres != 200) && (sisbios_mode[myindex].yres != 240)) return -1; break; case 400: if(sisbios_mode[myindex].yres != 300) return -1; break; case 512: if(sisbios_mode[myindex].yres != 384) return -1; break; case 640: if((sisbios_mode[myindex].yres != 400) && (sisbios_mode[myindex].yres != 480)) return -1; break; case 800: if(sisbios_mode[myindex].yres != 600) return -1; break; case 1024: if(sisbios_mode[myindex].yres != 768) return -1; break; case 1280: if((sisbios_mode[myindex].yres != 960) && (sisbios_mode[myindex].yres != 1024)) return -1; if(sisbios_mode[myindex].yres == 960) { if(sishw_ext.ulCRT2LCDType == LCD_1400x1050) return -1; } break; case 1400: if(sisbios_mode[myindex].yres != 1050) return -1; break; case 1600: if(sisbios_mode[myindex].yres != 1200) return -1; break; default: return -1; } } break; case CRT2_TV: switch (sisbios_mode[myindex].xres) { case 512: if(vbflags & VB_CHRONTEL) return -1; /* fall through */ case 640: case 800: break; case 720: if (vbflags & VB_CHRONTEL) return -1; if (vbflags & TV_NTSC) { if (sisbios_mode[myindex].yres != 480) { return -1; } } else if (vbflags & TV_PAL) { if (sisbios_mode[myindex].yres != 576) { return -1; } } break; case 1024: if (vbflags & VB_301) return -1; if (vbflags & VB_CHRONTEL) { if(ivideo.chip < SIS_315H) { return(-1); } } if (vbflags & TV_NTSC) { if(sisbios_mode[myindex].bpp == 32) { return(-1); } } break; default: return -1; } break; case CRT2_VGA: if(sisbios_mode[myindex].xres > 1280) return -1; break; } return(myindex);}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; sisfb_tvplug = sis_crt2type[i].tvplug_no; break; } i++; } if(sisfb_crt2type < 0) printk(KERN_ERR "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_ERR "sisfb: Invalid queuemode type: %s\n", name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -