⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sis_main.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	    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 + -