📄 sis_main.c
字号:
}static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx){ u16 xres, yres; int i = 0; xres = sisbios_mode[mode_idx].xres; yres = sisbios_mode[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) <= 3) { 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; } else if((rate - sisfb_vrate[i].refresh) <= 2) { DPRINTK("sisfb: Adjusting rate from %d down to %d\n", rate, sisfb_vrate[i].refresh); sisfb_rate_idx = sisfb_vrate[i].idx; 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 void sisfb_search_tvstd(const char *name){ int i = 0; if(name == NULL) return; while (sis_tvtype[i].type_no != -1) { if (!strcmp(name, sis_tvtype[i].name)) { ivideo.vbflags |= sis_tvtype[i].type_no; break; } i++; }}static BOOLEAN sisfb_bridgeisslave(void){ unsigned char P1_00; if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE; inSISIDXREG(SISPART1,0x00,P1_00); if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { return TRUE; } else { return FALSE; }}static BOOLEAN sisfbcheckvretracecrt1(void){ unsigned char temp; inSISIDXREG(SISCR,0x17,temp); if(!(temp & 0x80)) return FALSE; if(sisvga_engine == SIS_315_VGA) { inSISIDXREG(SISSR,0x1f,temp); if(temp & 0xc0) return FALSE; } if(inSISREG(SISINPSTAT) & 0x08) return TRUE; else return FALSE;}static BOOLEAN sisfbcheckvretracecrt2(void){ unsigned char temp, reg; switch(sisvga_engine) { case SIS_300_VGA: reg = 0x25; break; case SIS_315_VGA: reg = 0x30; break; default: return FALSE; } inSISIDXREG(SISPART1, reg, temp); if(temp & 0x02) return FALSE; else return TRUE;}static BOOLEAN sisfb_CheckVBRetrace(void) { if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { if(sisfb_bridgeisslave()) { return(sisfbcheckvretracecrt1()); } else { return(sisfbcheckvretracecrt2()); } } return(sisfbcheckvretracecrt1());}/* ----------- FBDev related routines for all series ----------- */static void sisfb_set_vparms(void){ switch(ivideo.video_bpp) { case 8: ivideo.DstColor = 0x0000; ivideo.SiS310_AccelDepth = 0x00000000; ivideo.video_cmap_len = 256; break; case 16: ivideo.DstColor = 0x8000; ivideo.SiS310_AccelDepth = 0x00010000; ivideo.video_cmap_len = 16; break; case 32: ivideo.DstColor = 0xC000; ivideo.SiS310_AccelDepth = 0x00020000; ivideo.video_cmap_len = 16; break; default: ivideo.video_cmap_len = 16; printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp); ivideo.accel = 0; break; }}static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info){ unsigned int htotal = 0, vtotal = 0; double drate = 0, hrate = 0; int found_mode = 0; int old_mode; u32 pixclock; htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; vtotal = var->upper_margin + var->lower_margin + var->vsync_len; pixclock = var->pixclock; if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { vtotal += var->yres; vtotal <<= 1; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { vtotal += var->yres; vtotal <<= 2; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { vtotal += var->yres; vtotal <<= 1; } else vtotal += var->yres; if(!(htotal) || !(vtotal)) { DPRINTK("sisfb: Invalid 'var' information\n"); return -EINVAL; } if(pixclock && htotal && vtotal) { drate = 1E12 / pixclock; hrate = drate / htotal; ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); } else ivideo.refresh_rate = 60;#if 0 printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n", var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);#endif 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_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags); else sisfb_mode_idx = -1; if(sisfb_mode_idx < 0) { printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres, var->yres, var->bits_per_pixel); sisfb_mode_idx = old_mode; return -EINVAL; } if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) { sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {#else if(isactive) {#endif sisfb_pre_setmode(); if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) { printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no); return -EINVAL; } outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres; ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres; ivideo.org_x = ivideo.org_y = 0; ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); ivideo.accel = 0; if(sisfb_accel) { ivideo.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0; } sisfb_set_vparms(); ivideo.current_width = ivideo.video_width; ivideo.current_height = ivideo.video_height; ivideo.current_bpp = ivideo.video_bpp; ivideo.current_htotal = htotal; ivideo.current_vtotal = vtotal; ivideo.current_pixclock = var->pixclock; ivideo.current_refresh_rate = ivideo.refresh_rate;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate;#endif sisfb_post_setmode(); } return 0;}static int sisfb_pan_var(struct fb_var_screeninfo *var){ unsigned int base; if (var->xoffset > (var->xres_virtual - var->xres)) { return -EINVAL; } if(var->yoffset > (var->yres_virtual - var->yres)) { return -EINVAL; } base = var->yoffset * var->xres_virtual + var->xoffset; /* calculate base bpp dep. */ switch(var->bits_per_pixel) { case 16: base >>= 1; break; case 32: break; case 8: default: base >>= 2; break; } outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); if(sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); } if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01); outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); if(sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); } } return 0;}static void sisfb_bpp_to_var(struct fb_var_screeninfo *var){ switch(var->bits_per_pixel) { case 8: var->red.offset = var->green.offset = var->blue.offset = 0; var->red.length = var->green.length = var->blue.length = 6; ivideo.video_cmap_len = 256; break; case 16: 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; ivideo.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; ivideo.video_cmap_len = 16; break; }}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; rec->vbflags = ivideo.vbflags; rec->currentvbflags = ivideo.currentvbflags;}/* ------------ FBDev related routines for 2.4 series ----------- */#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)static void sisfb_crtc_to_var(struct fb_var_screeninfo *var){ u16 VRE, VBE, VRS, VBS, VDE, VT; u16 HRE, HBE, HRS, HBS, HDE, HT; u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; int A, B, C, D, E, F, temp; double hrate, drate; inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data); if (sr_data & SIS_INTERLACED_MODE) var->vmode = FB_VMODE_INTERLACED; else var->vmode = FB_VMODE_NONINTERLACED; switch ((sr_data & 0x1C) >> 2) { case SIS_8BPP_COLOR_MODE: var->bits_per_pixel = 8; break; case SIS_16BPP_COLOR_MODE: var->bits_per_pixel = 16; break; case SIS_32BPP_COLOR_MODE: var->bits_per_pixel = 32; break; } sisfb_bpp_to_var(var); inSISIDXREG(SISSR, 0x0A, sr_data); inSISIDXREG(SISCR, 0x06, cr_data); inSISIDXREG(SISCR, 0x07, cr_data2); VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) | ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10); A = VT + 2; inSISIDXREG(SISCR, 0x12, cr_data); VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) | ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9); E = VDE + 1; inSISIDXREG(SISCR, 0x10, cr_data); VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) | ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7); F = VRS + 1 - E; inSISIDXREG(SISCR, 0x15, cr_data); inSISIDXREG(SISCR, 0x09, cr_data3); if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE; VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) | ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8); inSISIDXREG(SISCR, 0x16, cr_data); VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); temp = VBE - ((E - 1) & 511); B = (temp > 0) ? temp : (temp + 512); inSISIDXREG(SISCR, 0x11, cr_data); VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); temp = VRE - ((E + F - 1) & 31); C = (temp > 0) ? temp : (temp + 32); D = B - F - C; var->yres = E; var->upper_margin = D; var->lower_margin = F; var->vsync_len = C; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { var->yres <<= 1; var->upper_margin <<= 1; var->lower_margin <<= 1; var->vsync_len <<= 1; } else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { var->yres >>= 1; var->upper_margin >>= 1; var->lower_margin >>= 1; var->vsync_len >>= 1; } inSISIDXREG(SISSR, 0x0b, sr_data); inSISIDXREG(SISCR, 0x00, cr_data); HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); A = HT + 5; inSISIDXREG(SISCR, 0x01, cr_data); HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); E = HDE + 1; inSISIDXREG(SISCR, 0x04, cr_data); HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); F = HRS - E - 3; inSISIDXREG(SISCR, 0x02, cr_data); HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); inSISIDXREG(SISSR, 0x0c, sr_data); inSISIDXREG(SISCR, 0x03, cr_data); inSISIDXREG(SISCR, 0x05, cr_data2); HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) | ((u16) (sr_data & 0x03) << 6); HRE = (cr_data2 & 0x1f) | ((sr_data & 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; if((var->xres == 320) && (var->yres == 200 || var->yres == 240)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -