📄 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 * * 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 + -