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

📄 acornfb.c

📁 S3C44B0X下的LCD (framebuffer)驱动资料与相关代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * If minimum screen size is greater than that we have	 * available, reject it.	 */	if (min_size > current_par.screen_size)		return -EINVAL;	/* Find int 'y', such that y * fll == s * sam < maxsize	 * y = s * sam / fll; s = maxsize / sam	 */	for (size = current_par.screen_size; min_size <= size;	     size -= sam_size) {		nr_y = size / font_line_len;		if (nr_y * font_line_len == size)			break;	}	if (var->accel_flags & FB_ACCELF_TEXT) {		if (min_size > size) {			/*			 * failed, use ypan			 */			size = current_par.screen_size;			var->yres_virtual = size / (font_line_len / fontht);		} else			var->yres_virtual = nr_y * fontht;	}	current_par.screen_end = current_par.screen_base_p + size;	/*	 * Fix yres & yoffset if needed.	 */	if (var->yres > var->yres_virtual)		var->yres = var->yres_virtual;	if (var->vmode & FB_VMODE_YWRAP) {		if (var->yoffset > var->yres_virtual)			var->yoffset = var->yres_virtual;	} else {		if (var->yoffset + var->yres > var->yres_virtual)			var->yoffset = var->yres_virtual - var->yres;	}	/* hsync_len must be even */	var->hsync_len = (var->hsync_len + 1) & ~1;#ifdef HAS_VIDC	/* left_margin must be odd */	if ((var->left_margin & 1) == 0) {		var->left_margin -= 1;		var->right_margin += 1;	}	/* right_margin must be odd */	var->right_margin |= 1;#elif defined(HAS_VIDC20)	/* left_margin must be even */	if (var->left_margin & 1) {		var->left_margin += 1;		var->right_margin -= 1;	}	/* right_margin must be even */	if (var->right_margin & 1)		var->right_margin += 1;#endif	if (var->vsync_len < 1)		var->vsync_len = 1;	return 0;}static intacornfb_validate_timing(struct fb_var_screeninfo *var,			struct fb_monspecs *monspecs){	unsigned long hs, vs;	/*	 * hs(Hz) = 10^12 / (pixclock * xtotal)	 * vs(Hz) = hs(Hz) / ytotal	 *	 * No need to do long long divisions or anything	 * like that if you factor it correctly	 */	hs = 1953125000 / var->pixclock;	hs = hs * 512 /	     (var->xres + var->left_margin + var->right_margin + var->hsync_len);	vs = hs /	     (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);	return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&		hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;}static inline voidacornfb_update_dma(struct fb_var_screeninfo *var){	int off = (var->yoffset * var->xres_virtual *		   var->bits_per_pixel) >> 3;#if defined(HAS_MEMC)	memc_write(VDMA_INIT, off >> 2);#elif defined(HAS_IOMD)	iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);#endif}static intacornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,		  u_int *trans, struct fb_info *info){	if (regno >= current_par.palette_size)		return 1;	acornfb_palette_decode(regno, red, green, blue, trans);	return 0;}/* * We have to take note of the VIDC20's 16-bit palette here. * The VIDC20 looks up a 16 bit pixel as follows: * *   bits   111111 *          5432109876543210 *   red            ++++++++  (8 bits,  7 to 0) *  green       ++++++++      (8 bits, 11 to 4) *   blue   ++++++++          (8 bits, 15 to 8) * * We use a pixel which looks like: * *   bits   111111 *          5432109876543210 *   red               +++++  (5 bits,  4 to  0) *  green         +++++       (5 bits,  9 to  5) *   blue    +++++            (5 bits, 14 to 10) */static intacornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,		  u_int trans, struct fb_info *info){	union palette pal;	int bpp = fb_display[current_par.currcon].var.bits_per_pixel;	if (regno >= current_par.palette_size)		return 1;	pal = acornfb_palette_encode(regno, red, green, blue, trans);	current_par.palette[regno] = pal;#ifdef FBCON_HAS_CFB32	if (bpp == 32 && regno < 16) {		current_par.cmap.cfb32[regno] =				regno | regno << 8 | regno << 16;	}#endif#ifdef FBCON_HAS_CFB16	if (bpp == 16 && regno < 16) {		int i;		current_par.cmap.cfb16[regno] =				regno | regno << 5 | regno << 10;		pal.p = 0;		vidc_writel(0x10000000);		for (i = 0; i < 256; i += 1) {			pal.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;			pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;			pal.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;			vidc_writel(pal.p);			/* Palette register pointer auto-increments */		}	} else#endif		acornfb_palette_write(regno, pal);	return 0;}static intacornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,		 struct fb_info *info){	int err = 0;	if (con == current_par.currcon)		err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info);	else if (fb_display[con].cmap.len)		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);	else		fb_copy_cmap(fb_default_cmap(current_par.palette_size),			     cmap, kspc ? 0 : 2);	return err;}static intacornfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,		 struct fb_info *info){	int err = 0;	if (!fb_display[con].cmap.len)		err = fb_alloc_cmap(&fb_display[con].cmap,				    current_par.palette_size, 0);	if (!err) {		if (con == current_par.currcon)			err = fb_set_cmap(cmap, kspc, acornfb_setcolreg,					  info);		else			fb_copy_cmap(cmap, &fb_display[con].cmap,				     kspc ? 0 : 1);	}	return err;}static intacornfb_decode_var(struct fb_var_screeninfo *var, int con){	int err;#if defined(HAS_VIDC20)	var->red.offset    = 0;	var->red.length    = 8;	var->green         = var->red;	var->blue          = var->red;	var->transp.offset = 0;	var->transp.length = 4;#elif defined(HAS_VIDC)	var->red.length	   = 4;	var->green         = var->red;	var->blue          = var->red;	var->transp.length = 1;#endif	switch (var->bits_per_pixel) {#ifdef FBCON_HAS_MFB	case 1:		break;#endif#ifdef FBCON_HAS_CFB2	case 2:		break;#endif#ifdef FBCON_HAS_CFB4	case 4:		break;#endif#ifdef FBCON_HAS_CFB8	case 8:		break;#endif#ifdef FBCON_HAS_CFB16	case 16:		var->red.offset    = 0;		var->red.length    = 5;		var->green.offset  = 5;		var->green.length  = 5;		var->blue.offset   = 10;		var->blue.length   = 5;		var->transp.offset = 15;		var->transp.length = 1;		break;#endif#ifdef FBCON_HAS_CFB32	case 32:		var->red.offset    = 0;		var->red.length    = 8;		var->green.offset  = 8;		var->green.length  = 8;		var->blue.offset   = 16;		var->blue.length   = 8;		var->transp.offset = 24;		var->transp.length = 4;		break;#endif	default:		return -EINVAL;	}	/*	 * Check to see if the pixel rate is valid.	 */	if (!var->pixclock || !acornfb_valid_pixrate(var->pixclock))		return -EINVAL;	/*	 * Validate and adjust the resolution to	 * match the video generator hardware.	 */	err = acornfb_adjust_timing(var, con);	if (err)		return err;	/*	 * Validate the timing against the	 * monitor hardware.	 */	return acornfb_validate_timing(var, &fb_info.monspecs);}static intacornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){	struct display *display;	memset(fix, 0, sizeof(struct fb_fix_screeninfo));	strcpy(fix->id, "Acorn");	if (con >= 0)		display = fb_display + con;	else		display = &global_disp;	fix->smem_start	 = current_par.screen_base_p;	fix->smem_len	 = current_par.screen_size;	fix->type	 = display->type;	fix->type_aux	 = display->type_aux;	fix->xpanstep	 = 0;	fix->ypanstep	 = display->ypanstep;	fix->ywrapstep	 = display->ywrapstep;	fix->visual	 = display->visual;	fix->line_length = display->line_length;	fix->accel	 = FB_ACCEL_NONE;	return 0;}static intacornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){	if (con == -1) {		*var = global_disp.var;	} else		*var = fb_display[con].var;	return 0;}static intacornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){	struct display *display;	int err, chgvar = 0;	if (con >= 0)		display = fb_display + con;	else		display = &global_disp;	err = acornfb_decode_var(var, con);	if (err)		return err;	switch (var->activate & FB_ACTIVATE_MASK) {	case FB_ACTIVATE_TEST:		return 0;	case FB_ACTIVATE_NXTOPEN:	case FB_ACTIVATE_NOW:		break;	default:		return -EINVAL;	}	if (con >= 0) {		if (display->var.xres != var->xres)			chgvar = 1;		if (display->var.yres != var->yres)			chgvar = 1;		if (display->var.xres_virtual != var->xres_virtual)			chgvar = 1;		if (display->var.yres_virtual != var->yres_virtual)			chgvar = 1;		if (memcmp(&display->var.red, &var->red, sizeof(var->red)))			chgvar = 1;		if (memcmp(&display->var.green, &var->green, sizeof(var->green)))			chgvar = 1;		if (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))			chgvar = 1;	}	display->var = *var;	display->var.activate &= ~FB_ACTIVATE_ALL;	if (var->activate & FB_ACTIVATE_ALL)		global_disp.var = display->var;	switch (display->var.bits_per_pixel) {#ifdef FBCON_HAS_MFB	case 1:		current_par.palette_size = 2;		display->dispsw = &fbcon_mfb;		display->visual = FB_VISUAL_MONO10;		break;#endif#ifdef FBCON_HAS_CFB2	case 2:		current_par.palette_size = 4;		display->dispsw = &fbcon_cfb2;		display->visual = FB_VISUAL_PSEUDOCOLOR;		break;#endif#ifdef FBCON_HAS_CFB4	case 4:		current_par.palette_size = 16;		display->dispsw = &fbcon_cfb4;		display->visual = FB_VISUAL_PSEUDOCOLOR;		break;#endif#ifdef FBCON_HAS_CFB8	case 8:		current_par.palette_size = VIDC_PALETTE_SIZE;		display->dispsw = &fbcon_cfb8;#ifdef HAS_VIDC		display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;#else		display->visual = FB_VISUAL_PSEUDOCOLOR;#endif		break;#endif#ifdef FBCON_HAS_CFB16	case 16:		current_par.palette_size = 32;		display->dispsw = &fbcon_cfb16;		display->dispsw_data = current_par.cmap.cfb16;		display->visual = FB_VISUAL_DIRECTCOLOR;		break;#endif#ifdef FBCON_HAS_CFB32	case 32:		current_par.palette_size = VIDC_PALETTE_SIZE;		display->dispsw = &fbcon_cfb32;		display->dispsw_data = current_par.cmap.cfb32;		display->visual = FB_VISUAL_TRUECOLOR;		break;#endif	default:		display->dispsw = &fbcon_dummy;		break;	}	display->screen_base	= (char *)current_par.screen_base;	display->type		= FB_TYPE_PACKED_PIXELS;	display->type_aux	= 0;	display->ypanstep	= 1;	display->ywrapstep	= 1;	display->line_length	=	display->next_line      = (var->xres * var->bits_per_pixel) / 8;	display->can_soft_blank	= display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;	display->inverse	= 0;	if (chgvar && info && info->changevar)		info->changevar(con);	if (con == current_par.currcon) {		struct fb_cmap *cmap;		unsigned long start, size;		int control;#if defined(HAS_MEMC)		start   = 0;		size    = current_par.screen_size - VDMA_XFERSIZE;		control = 0;		memc_write(VDMA_START, start);		memc_write(VDMA_END, size >> 2);#elif defined(HAS_IOMD)		start = current_par.screen_base_p;		size  = current_par.screen_end;		if (current_par.using_vram) {			size -= current_par.vram_half_sam;			control = DMA_CR_E | (current_par.vram_half_sam / 256);		} else {			size -= 16;			control = DMA_CR_E | DMA_CR_D | 16;		}		iomd_writel(start,   IOMD_VIDSTART);		iomd_writel(size,    IOMD_VIDEND);		iomd_writel(control, IOMD_VIDCR);#endif		acornfb_update_dma(var);		acornfb_set_timing(var);		if (display->cmap.len)			cmap = &display->cmap;		else			cmap = fb_default_cmap(current_par.palette_size);		fb_set_cmap(cmap, 1, acornfb_setcolreg, info);	}	return 0;}static intacornfb_pan_display(struct fb_var_screeninfo *var, int con,		    struct fb_info *info){	u_int y_bottom;	if (var->xoffset)		return -EINVAL;	y_bottom = var->yoffset;	if (!(var->vmode & FB_VMODE_YWRAP))		y_bottom += var->yres;	if (y_bottom > fb_display[con].var.yres_virtual)		return -EINVAL;	acornfb_update_dma(var);	fb_display[con].var.yoffset = var->yoffset;	if (var->vmode & FB_VMODE_YWRAP)		fb_display[con].var.vmode |= FB_VMODE_YWRAP;	else		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;	return 0;}/* * Note that we are entered with the kernel locked. */static intacornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){	unsigned long off, start;	u32 len;	off = vma->vm_pgoff << PAGE_SHIFT;	start = current_par.screen_base_p;	len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size;	start &= PAGE_MASK;	if ((vma->vm_end - vma->vm_start + off) > len)		return -EINVAL;	off += start;	vma->vm_pgoff = off >> PAGE_SHIFT;#ifdef CONFIG_CPU_32	pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;#endif	/*	 * Don't alter the page protection flags; we want to keep the area	 * cached for better performance.  This does mean that we may miss	 * some updates to the screen occasionally, but process switches	 * should cause the caches and buffers to be flushed often enough.	 */	if (io_remap_page_range(vma->vm_start, off,				vma->vm_end - vma->vm_start,				vma->vm_page_prot))		return -EAGAIN;	return 0;}static struct fb_ops acornfb_ops = {	owner:		THIS_MODULE,	fb_get_fix:	acornfb_get_fix,	fb_get_var:	acornfb_get_var,	fb_set_var:	acornfb_set_var,	fb_get_cmap:	acornfb_get_cmap,	fb_set_cmap:	acornfb_set_cmap,	fb_pan_display:	acornfb_pan_display,	fb_mmap:	acornfb_mmap,};static intacornfb_updatevar(int con, struct fb_info *info){	if (con == current_par.currcon)		acornfb_update_dma(&fb_display[con].var);	return 0;}static intacornfb_switch(int con, struct fb_info *info){	struct fb_cmap *cmap;	if (current_par.currcon >= 0) {

⌨️ 快捷键说明

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