📄 sis_main.c
字号:
/* * 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 + -