📄 sis_main.c
字号:
sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno){ USHORT temp, i, realcrtno = crtno; u8 buffer[256]; monitor->datavalid = FALSE; if(crtno) { if(ivideo->vbflags & CRT2_LCD) realcrtno = 1; else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2; else return; } if((ivideo->sisfb_crt1off) && (!crtno)) return; temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, realcrtno, 0, &buffer[0]); if((!temp) || (temp == 0xffff)) { printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); return; } else { printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1); printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n", crtno + 1, (temp & 0x1a) ? "" : "[none of the supported]", (temp & 0x02) ? "2 " : "", (temp & 0x08) ? "D&P" : "", (temp & 0x10) ? "FPDI-2" : ""); if(temp & 0x02) { i = 3; /* Number of retrys */ do { temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, realcrtno, 1, &buffer[0]); } while((temp) && i--); if(!temp) { if(sisfb_interpret_edid(monitor, &buffer[0])) { printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n", monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax, monitor->dclockmax / 1000); } else { printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1); } } else { printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1); } } else { printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n"); } }}static BOOLEANsisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate){ int htotal, vtotal; unsigned int dclock, hsync; if(!monitor->datavalid) return TRUE; if(mode_idx < 0) return FALSE; /* Skip for 320x200, 320x240, 640x400 */ switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) { case 0x59: case 0x41: case 0x4f: case 0x50: case 0x56: case 0x53: case 0x2f: case 0x5d: case 0x5e: return TRUE;#ifdef CONFIG_FB_SIS_315 case 0x5a: case 0x5b: if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;#endif } if(rate < (monitor->vmin - 1)) return FALSE; if(rate > (monitor->vmax + 1)) return FALSE; if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext, sisbios_mode[mode_idx].mode_no[ivideo->mni], &htotal, &vtotal, rate_idx)) { dclock = (htotal * vtotal * rate) / 1000; if(dclock > (monitor->dclockmax + 1000)) return FALSE; hsync = dclock / htotal; if(hsync < (monitor->hmin - 1)) return FALSE; if(hsync > (monitor->hmax + 1)) return FALSE; } else { return FALSE; } return TRUE;}static intsisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags){ u16 xres=0, yres, myres;#ifdef CONFIG_FB_SIS_300 if(ivideo->sisvga_engine == SIS_300_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1); }#endif#ifdef CONFIG_FB_SIS_315 if(ivideo->sisvga_engine == SIS_315_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1); }#endif myres = sisbios_mode[myindex].yres; switch(vbflags & VB_DISPTYPE_DISP2) { case CRT2_LCD: xres = ivideo->lcdxres; yres = ivideo->lcdyres; if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) { if(sisbios_mode[myindex].xres > xres) return(-1); if(myres > yres) return(-1); } if(vbflags & (VB_LVDS | VB_30xBDH)) { if(sisbios_mode[myindex].xres == 320) { if((myres == 240) || (myres == 480)) { if(!ivideo->sisfb_fstn) { if(sisbios_mode[myindex].mode_no[1] == 0x5a || sisbios_mode[myindex].mode_no[1] == 0x5b) return(-1); } else { if(sisbios_mode[myindex].mode_no[1] == 0x50 || sisbios_mode[myindex].mode_no[1] == 0x56 || sisbios_mode[myindex].mode_no[1] == 0x53) return(-1); } } } } if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn, ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) { return(-1); } break; case CRT2_TV: if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0) < 0x14) { return(-1); } break; case CRT2_VGA: if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0) < 0x14) { return(-1); } break; } return(myindex);}static u8sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx){ u16 xres, yres; int i = 0; xres = sisbios_mode[mode_idx].xres; yres = sisbios_mode[mode_idx].yres; ivideo->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) { ivideo->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); ivideo->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); ivideo->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); ivideo->rate_idx = sisfb_vrate[i].idx; break; } } i++; } if(ivideo->rate_idx > 0) { return ivideo->rate_idx; } else { printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n", rate, xres, yres); return 0; }}static BOOLEANsisfb_bridgeisslave(struct sis_video_info *ivideo){ unsigned char P1_00; if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE; inSISIDXREG(SISPART1,0x00,P1_00); if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { return TRUE; } else { return FALSE; }}static BOOLEANsisfballowretracecrt1(struct sis_video_info *ivideo){ u8 temp; inSISIDXREG(SISCR,0x17,temp); if(!(temp & 0x80)) return FALSE; inSISIDXREG(SISSR,0x1f,temp); if(temp & 0xc0) return FALSE; return TRUE;}static BOOLEANsisfbcheckvretracecrt1(struct sis_video_info *ivideo){ if(!sisfballowretracecrt1(ivideo)) return FALSE; if(inSISREG(SISINPSTAT) & 0x08) return TRUE; else return FALSE;}static voidsisfbwaitretracecrt1(struct sis_video_info *ivideo){ int watchdog; if(!sisfballowretracecrt1(ivideo)) return; watchdog = 65536; while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog); watchdog = 65536; while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);}static BOOLEANsisfbcheckvretracecrt2(struct sis_video_info *ivideo){ unsigned char temp, reg; switch(ivideo->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 BOOLEANsisfb_CheckVBRetrace(struct sis_video_info *ivideo){ if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { if(sisfb_bridgeisslave(ivideo)) { return(sisfbcheckvretracecrt1(ivideo)); } else { return(sisfbcheckvretracecrt2(ivideo)); } } return(sisfbcheckvretracecrt1(ivideo));}static u32sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount){ u8 idx, reg1, reg2, reg3, reg4; u32 ret = 0; (*vcount) = (*hcount) = 0; if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) { ret |= (FB_VBLANK_HAVE_VSYNC | FB_VBLANK_HAVE_HBLANK | FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_HCOUNT); switch(ivideo->sisvga_engine) { case SIS_300_VGA: idx = 0x25; break; default: case SIS_315_VGA: idx = 0x30; break; } inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */ inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */ inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */ inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */ if(!(reg1 & 0x01)) ret |= FB_VBLANK_VBLANKING; if(!(reg1 & 0x02)) ret |= FB_VBLANK_VSYNCING; if(!(reg4 & 0x80)) ret |= FB_VBLANK_HBLANKING; (*vcount) = reg3 | ((reg4 & 0x70) << 4); (*hcount) = reg2 | ((reg4 & 0x0f) << 8); } else if(sisfballowretracecrt1(ivideo)) { ret |= (FB_VBLANK_HAVE_VSYNC | FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_HCOUNT); reg1 = inSISREG(SISINPSTAT); if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING; if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; inSISIDXREG(SISCR,0x20,reg1); inSISIDXREG(SISCR,0x1b,reg1); inSISIDXREG(SISCR,0x1c,reg2); inSISIDXREG(SISCR,0x1d,reg3); (*vcount) = reg2 | ((reg3 & 0x07) << 8); (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3; } return ret;}static intsisfb_myblank(struct sis_video_info *ivideo, int blank){ u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; BOOLEAN backlight = TRUE; switch(blank) { case 0: /* on */ sr01 = 0x00; sr11 = 0x00; sr1f = 0x00; cr63 = 0x00; p2_0 = 0x20; p1_13 = 0x00; backlight = TRUE; break; case 1: /* blank */ sr01 = 0x20; sr11 = 0x00; sr1f = 0x00; cr63 = 0x00; p2_0 = 0x20; p1_13 = 0x00; backlight = TRUE; break; case 2: /* no vsync */ sr01 = 0x20; sr11 = 0x08; sr1f = 0x80; cr63 = 0x40; p2_0 = 0x40; p1_13 = 0x80; backlight = FALSE; break; case 3: /* no hsync */ sr01 = 0x20; sr11 = 0x08; sr1f = 0x40; cr63 = 0x40; p2_0 = 0x80; p1_13 = 0x40; backlight = FALSE; break; case 4: /* off */ sr01 = 0x20; sr11 = 0x08; sr1f = 0xc0; cr63 = 0x40; p2_0 = 0xc0; p1_13 = 0xc0; backlight = FALSE; break; default: return 1; } if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) { if( (!ivideo->sisfb_thismonitor.datavalid) || ((ivideo->sisfb_thismonitor.datavalid) && (ivideo->sisfb_thismonitor.feature & 0xe0))) { if(ivideo->sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63); } if(!(sisfb_bridgeisslave(ivideo))) { setSISIDXREG(SISSR, 0x01, ~0x20, sr01); setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f); } } } if(ivideo->currentvbflags & CRT2_LCD) { if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) { if(backlight) { SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext); } else { SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext); } } else if(ivideo->sisvga_engine == SIS_315_VGA) { if(ivideo->vbflags & VB_CHRONTEL) { if(backlight) { SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext); } else { SiS_Chrontel701xBLOff(&ivideo->SiS_Pr); } } } if(((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) || ((ivideo->sisvga_engine == SIS_315_VGA) && ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { setSISIDXREG(SISSR, 0x11, ~0x0c, sr11); } if(ivideo->sisvga_engine == SIS_300_VGA) { if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && (!(ivideo->vbflags & VB_30xBDH))) { setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13); } } else if(ivideo->sisvga_engine == SIS_315_VGA) { if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && (!(ivideo->vbflags & VB_30xBDH))) { setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); } } } else if(ivideo->currentvbflags & CRT2_VGA) { if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) { setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); } } return(0);}/* ----------- FBDev related routines for all series ----------- */static intsisfb_get_cmap_len(const struct fb_var_screeninfo *var){ return (var->bits_per_pixel == 8) ? 256 : 16;}static voidsisfb_set_vparms(struct sis_video_info *ivideo){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -