📄 sis_main.c
字号:
j = 0x36; for(i=0; i<4; i++) { if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 && buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd && buffer[j + 4] == 0x00) { monitor->hmin = buffer[j + 7]; monitor->hmax = buffer[j + 8]; monitor->vmin = buffer[j + 5]; monitor->vmax = buffer[j + 6]; monitor->dclockmax = buffer[j + 9] * 10 * 1000; monitor->datavalid = TRUE; break; } j += 18; } } if(!monitor->datavalid) { /* Otherwise: Get a range from the list of supported * Estabished Timings. This is not entirely accurate, * because fixed frequency monitors are not supported * that way. */ monitor->hmin = 65535; monitor->hmax = 0; monitor->vmin = 65535; monitor->vmax = 0; monitor->dclockmax = 0; emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16); for(i = 0; i < 13; i++) { if(emodes & sisfb_ddcsmodes[i].mask) { if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h; if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1; if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v; if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v; if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d; } } index = 0x26; for(i = 0; i < 8; i++) { xres = (buffer[index] + 31) * 8; switch(buffer[index + 1] & 0xc0) { case 0xc0: yres = (xres * 9) / 16; break; case 0x80: yres = (xres * 4) / 5; break; case 0x40: yres = (xres * 3) / 4; break; default: yres = xres; break; } refresh = (buffer[index + 1] & 0x3f) + 60; if((xres >= 640) && (yres >= 480)) { for(j = 0; j < 8; j++) { if((xres == sisfb_ddcfmodes[j].x) && (yres == sisfb_ddcfmodes[j].y) && (refresh == sisfb_ddcfmodes[j].v)) { if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h; if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1; if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v; if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v; if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d; } } } index += 2; } if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) { monitor->datavalid = TRUE; } } return monitor->datavalid;}static void __devinitsisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno){ unsigned short temp, i, realcrtno = crtno; unsigned char 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], ivideo->vbflags2); 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], ivideo->vbflags2); } 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"); } }}/* -------------- Mode validation --------------- */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, 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) && (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) { if(sisbios_mode[myindex].xres > xres) return -1; if(myres > yres) return -1; } if(ivideo->sisfb_fstn) { if(sisbios_mode[myindex].xres == 320) { if(myres == 240) { switch(sisbios_mode[myindex].mode_no[1]) { case 0x50: myindex = MODE_FSTN_8; break; case 0x56: myindex = MODE_FSTN_16; break; case 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, ivideo->vbflags2) < 0x14) { return -1; } break; case CRT2_TV: if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { return -1; } break; case CRT2_VGA: if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { return -1; } break; } return myindex;}static u8sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx){ int i = 0; u16 xres = sisbios_mode[mode_idx].xres; u16 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->vbflags2 & VB2_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 TRUE; else return FALSE;}static BOOLEANsisfb_CheckVBRetrace(struct sis_video_info *ivideo){ if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { if(!sisfb_bridgeisslave(ivideo)) { 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 FB_BLANK_UNBLANK: /* on */ sr01 = 0x00; sr11 = 0x00; sr1f = 0x00; cr63 = 0x00; p2_0 = 0x20; p1_13 = 0x00; backlight = TRUE; break; case FB_BLANK_NORMAL: /* blank */ sr01 = 0x20; sr11 = 0x00; sr1f = 0x00; cr63 = 0x00; p2_0 = 0x20; p1_13 = 0x00; backlight = TRUE; break; case FB_BLANK_VSYNC_SUSPEND: /* no vsync */ sr01 = 0x20; sr11 = 0x08; sr1f = 0x80; cr63 = 0x40; p2_0 = 0x40; p1_13 = 0x80; backlight = FALSE; break; case FB_BLANK_HSYNC_SUSPEND: /* no hsync */ sr01 = 0x20; sr11 = 0x08; sr1f = 0x40; cr63 = 0x40; p2_0 = 0x80; p1_13 = 0x40; backlight = FALSE; break; case FB_BLANK_POWERDOWN: /* off */ sr01 = 0x20; sr11 = 0x08; sr1f = 0xc0; cr63 = 0x40; p2_0 = 0xc0; p1_13 = 0xc0; backlight = FALSE; break; default: return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -