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

📄 sis_main.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
{	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;	double drate = 0, hrate = 0;	int found_mode = 0;	int refresh_rate, search_idx;	BOOLEAN recalc_clock = FALSE;	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)) {		SISFAIL("sisfb: no valid timing data");	}	search_idx = 0;	while( (sisbios_mode[search_idx].mode_no != 0) &&	       (sisbios_mode[search_idx].xres <= var->xres) ) {		if( (sisbios_mode[search_idx].xres == var->xres) &&		    (sisbios_mode[search_idx].yres == var->yres) &&		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {		        if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {			   found_mode = 1;			   break;			}		}		search_idx++;	}	if(!found_mode) {                search_idx = 0;		while(sisbios_mode[search_idx].mode_no != 0) {		   if( (var->xres <= sisbios_mode[search_idx].xres) &&		       (var->yres <= sisbios_mode[search_idx].yres) &&		       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {		          if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {			     found_mode = 1;			     break;			  }		   }		   search_idx++;	        }		if(found_mode) {			printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",		   		var->xres, var->yres, var->bits_per_pixel,				sisbios_mode[search_idx].xres,				sisbios_mode[search_idx].yres,				var->bits_per_pixel);			var->xres = sisbios_mode[search_idx].xres;		      	var->yres = sisbios_mode[search_idx].yres;		} else {		   	printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n",				var->xres, var->yres, var->bits_per_pixel);		   	return -EINVAL;		}	}	if( ((ivideo.vbflags & VB_LVDS) ||			/* Slave modes on LVDS and 301B-DH */	     ((ivideo.vbflags & VB_301BDH) && (ivideo.currentvbflags & CRT2_LCD))) &&	    (var->bits_per_pixel == 8) ) {	    	refresh_rate = 60;		recalc_clock = TRUE;	} else if( (ivideo.current_htotal == htotal) &&		/* x=x & y=y & c=c -> assume depth change */	    	   (ivideo.current_vtotal == vtotal) &&	    	   (ivideo.current_pixclock == pixclock) ) {		drate = 1E12 / pixclock;	   	hrate = drate / htotal;	   	refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);	} else if( ( (ivideo.current_htotal != htotal) ||	/* x!=x | y!=y & c=c -> invalid pixclock */	    	     (ivideo.current_vtotal != vtotal) ) &&	    	   (ivideo.current_pixclock == var->pixclock) ) {		if(sisfb_lastrates[sisbios_mode[search_idx].mode_no]) {			refresh_rate = sisfb_lastrates[sisbios_mode[search_idx].mode_no];		} else if(sisfb_parm_rate != -1) {			refresh_rate = sisfb_parm_rate;		} else {			refresh_rate = 60;		}		recalc_clock = TRUE;	} else if((pixclock) && (htotal) && (vtotal)) {	   	drate = 1E12 / pixclock;	   	hrate = drate / htotal;	   	refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);	} else if(ivideo.current_refresh_rate) {		refresh_rate = ivideo.current_refresh_rate;		recalc_clock = TRUE;	} else {		refresh_rate = 60;		recalc_clock = TRUE;	}	/* Eventually recalculate timing and clock */	if(recalc_clock) {	   myrateindex = sisfb_search_refresh_rate(refresh_rate, search_idx);	   if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;	   var->pixclock = (u32) (1E12 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,						sisbios_mode[search_idx].mode_no, myrateindex));	   sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,		 			sisbios_mode[search_idx].mode_no, myrateindex,		 			&var->left_margin, &var->right_margin,		 			&var->upper_margin, &var->lower_margin,		 			&var->hsync_len, &var->vsync_len,		 			&var->sync, &var->vmode);	   if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {		var->pixclock <<= 1;	   }	}	/* Adapt RGB settings */	sisfb_bpp_to_var(var);			/* Sanity check for offsets */	if (var->xoffset < 0)		var->xoffset = 0;	if (var->yoffset < 0)		var->yoffset = 0;	/* Horiz-panning not supported */	if(var->xres != var->xres_virtual)		var->xres_virtual = var->xres;		if(sisfb_ypan) {	   /* TW: Now patch yres_virtual if we use panning */	   /* *** May I do this? *** */	   var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));	   if(var->yres_virtual <= var->yres) {	    	/* TW: Paranoia check */	        var->yres_virtual = var->yres;	   }	} else {	   if(var->yres != var->yres_virtual)		var->yres_virtual = var->yres;	   var->xoffset = 0;	   var->yoffset = 0;	}		/* Truncate offsets to maximum if too high */	if (var->xoffset > var->xres_virtual - var->xres)		var->xoffset = var->xres_virtual - var->xres - 1;	if (var->yoffset > var->yres_virtual - var->yres)		var->yoffset = var->yres_virtual - var->yres - 1;		/* Set everything else to 0 */	var->red.msb_right = 	    var->green.msb_right =	    var->blue.msb_right =	    var->transp.offset = var->transp.length = var->transp.msb_right = 0;			return 0;}static int sisfb_pan_display(struct fb_var_screeninfo *var,			     struct fb_info* info){	int err;	if (var->xoffset > (var->xres_virtual - var->xres))		return -EINVAL;	if (var->yoffset > (var->yres_virtual - var->yres))		return -EINVAL;	if (var->vmode & FB_VMODE_YWRAP) {		if (var->yoffset < 0 ||		    var->yoffset >= info->var.yres_virtual ||		    var->xoffset)		    	return -EINVAL;	} else {		if (var->xoffset + info->var.xres > info->var.xres_virtual ||		    var->yoffset + info->var.yres > info->var.yres_virtual)			return -EINVAL;	}    	if((err = sisfb_pan_var(var)) < 0) return err;	info->var.xoffset = var->xoffset;	info->var.yoffset = var->yoffset;	if (var->vmode & FB_VMODE_YWRAP)		info->var.vmode |= FB_VMODE_YWRAP;	else		info->var.vmode &= ~FB_VMODE_YWRAP;	return 0;}static int sisfb_mmap(struct fb_info *info, struct file *file,		      struct vm_area_struct *vma){	unsigned long start;	unsigned long off;	u32 len, mmio_off;	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;	off = vma->vm_pgoff << PAGE_SHIFT;	start = (unsigned long) ivideo.video_base;	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);#if 0	if (off >= len) {		off -= len;#endif	/* By Jake Page: Treat mmap request with offset beyond heapstart	 *               as request for mapping the mmio area 	 */	mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart);	if(off >= mmio_off) {		off -= mmio_off;				if(info->var.accel_flags) return -EINVAL;		start = (unsigned long) ivideo.mmio_base;		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);	}	start &= PAGE_MASK;	if((vma->vm_end - vma->vm_start + off) > len)	return -EINVAL;	off += start;	vma->vm_pgoff = off >> PAGE_SHIFT;	vma->vm_flags |= VM_IO;   /* by Jake Page; is that really needed? */#if defined(__i386__) || defined(__x86_64__)	if (boot_cpu_data.x86 > 3)		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;#endif	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,				vma->vm_page_prot))		return -EAGAIN;	return 0;}static int sisfb_blank(int blank, struct fb_info *info){	u8 reg;	if(sisfb_bridgeisslave()) return 1;	inSISIDXREG(SISCR, 0x17, reg);	if(blank > 0)		reg &= 0x7f;	else		reg |= 0x80;        outSISIDXREG(SISCR, 0x17, reg);	outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */	outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */        return(0);}#endif/* ----------- FBDev related routines for all series ---------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int sisfb_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg,		       struct fb_info *info)#elsestatic int sisfb_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg, int con,		       struct fb_info *info)#endif{	struct sis_memreq req;   	struct ap_data ap;	unsigned long a;		switch (cmd) {	   case FBIO_ALLOC:		if (!capable(CAP_SYS_RAWIO))			return -EPERM;		if (copy_from_user(&req, (void *)arg, sizeof(req)))			return -EFAULT;		sis_malloc(&req);		if (copy_to_user((void *)arg, &req, sizeof(req)))			return -EFAULT;		break;	   case FBIO_FREE:		if (!capable(CAP_SYS_RAWIO))			return -EPERM;		if(get_user(a, (unsigned long *) arg))			return -EFAULT;		sis_free(a);		break;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	   case FBIOGET_GLYPH:                sis_get_glyph(info,(SIS_GLYINFO *) arg);		break;	   case FBIOPUT_MODEINFO:		{			struct mode_info x;						if(copy_from_user(&x, (void *)arg, sizeof(struct mode_info)))				return -EFAULT;			ivideo.video_bpp        = x.bpp;			ivideo.video_width      = x.xres;			ivideo.video_height     = x.yres;			ivideo.video_vwidth     = x.v_xres;			ivideo.video_vheight    = x.v_yres;			ivideo.org_x            = x.org_x;			ivideo.org_y            = x.org_y;			ivideo.refresh_rate     = x.vrate;			ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);			sisfb_set_vparms();			break;		}#endif	   case FBIOGET_HWCINFO:		{			unsigned long *hwc_offset = (unsigned long *) arg;			if (sisfb_caps & HW_CURSOR_CAP)				return put_user(sisfb_hwcursor_vbase -				    (unsigned long) ivideo.video_vbase, hwc_offset);			else				return put_user(0, hwc_offset);		}	   case FBIOGET_DISPINFO:	   	if(copy_from_user(&ap, (void *)arg, sizeof(struct ap_data)))	   		return -EFAULT;		sis_dispinfo(&ap);	   	if(copy_to_user((void *)arg, &ap, sizeof(struct ap_data)))	   		return -EFAULT;		break;	   case SISFB_GET_INFO:  /* TW: New for communication with X driver */	        {	        	sisfb_info x;			x.sisfb_id = SISFB_ID;			x.sisfb_version = VER_MAJOR;			x.sisfb_revision = VER_MINOR;			x.sisfb_patchlevel = VER_LEVEL;			x.chip_id = ivideo.chip_id;			x.memory = ivideo.video_size / 1024;			x.heapstart = ivideo.heapstart / 1024;			x.fbvidmode = sisfb_mode_no;			x.sisfb_caps = sisfb_caps;			x.sisfb_tqlen = 512; /* yet unused */			x.sisfb_pcibus = ivideo.pcibus;			x.sisfb_pcislot = ivideo.pcislot;			x.sisfb_pcifunc = ivideo.pcifunc;			x.sisfb_lcdpdc = sisfb_detectedpdc;			x.sisfb_lcda = sisfb_detectedlcda;			x.sisfb_vbflags = ivideo.vbflags;			x.sisfb_currentvbflags = ivideo.currentvbflags;						if(copy_to_user((void *)arg, &x, sizeof(sisfb_info)))				return -EFAULT;	                break;		}	   case SISFB_GET_VBRSTATUS:	        {			unsigned long *vbrstatus = (unsigned long *) arg;			if(sisfb_CheckVBRetrace())				return put_user(1, vbrstatus);			else				return put_user(0, vbrstatus);		}	   default:		return -EINVAL;	}	return 0;}static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,			 struct fb_info *info){	memset(fix, 0, sizeof(struct fb_fix_screeninfo));#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		strcpy(fix->id, sis_fb_info.modename);#else	strcpy(fix->id, myid);#endif		fix->smem_start = ivideo.video_base;        if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {	    if (ivideo.video_size > 0x1000000) {	        fix->smem_len = 0xc00000;	    } else if (ivideo.video_size > 0x800000)		fix->smem_len = 0x800000;	    else		fix->smem_len = 0x400000;        } else		fix->smem_len = sisfb_mem * 1024;	fix->type        = FB_TYPE_PACKED_PIXELS;	fix->type_aux    = 0;	if(ivideo.video_bpp == 8)		fix->visual = FB_VISUAL_PSEUDOCOLOR;	else		fix->visual = FB_VISUAL_TRUECOLOR;	fix->xpanstep    = 0;        if(sisfb_ypan) 	 fix->ypanstep = 1;	fix->ywrapstep   = 0;	fix->line_length = ivideo.video_linelength;	fix->mmio_start  = ivideo.mmio_base;	fix->mmio_len    = sisfb_mmio_size;	if(sisvga_engine == SIS_300_VGA) 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR;	else if(ivideo.chip == SIS_330)	   fix->accel    = FB_ACCEL_SIS_XABRE;	else 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)			fix->reserved[0] = ivideo.video_size & 0xFFFF;	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;	fix->reserved[2] = sisfb_caps;#endif		return 0;}/* ----------------  fb_ops structures ----------------- */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)static struct fb_ops sisfb_ops = {	owner:		THIS_MODULE,	fb_get_fix:	sisfb_get_fix,	fb_get_var:	sisfb_get_var,	fb_set_var:	sisfb_set_var,	fb_get_cmap:	sisfb_get_cmap,	fb_set_cmap:	sisfb_set_cmap,        fb_pan_display:	sisfb_pan_display,	fb_ioctl:	sisfb_ioctl,	fb_mmap:	sisfb_mmap,};#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static struct fb_ops sisfb_ops = {	.owner        =	THIS_MODULE,	.fb_open      = sisfb_open,	.fb_release   = sisfb_release,	.fb_check_var = sisfb_check_var,	.fb_set_par   = sisfb_set_par,	.fb_setcolreg = sisfb_setcolreg,        .fb_pan_display = sisfb_pan_display,        .fb_blank     = sisfb_blank,	.fb_fillrect  = fbcon_sis_fillrect,	.fb_copyarea  = fbcon_sis_copyarea,	.fb_imageblit = cfb_imageblit,	.fb_cursor    = soft_cursor,		.fb_sync      = fbcon_sis_sync,	.fb_ioctl     =	sisfb_ioctl,	.fb_mmap      =	sisfb_mmap,};#endif/* ---------------- Chip generation dependent routines ---------------- */#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */static int sisfb_get_dram_size_300(void){	struct pci_dev *pdev = NULL;	int pdev_valid = 0;	u8  pci_data, reg;	u16 nbridge_id;	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;	   default:		nbridge_id = 0;		break;	}	if (nbridge_id == 0) {  /* 300 */	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);		ivideo.video_size =		        ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);	} else {		/* 540, 630, 730 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -