cyber2000fb.c

来自「linux下的VIDEO接口驱动程序」· C语言 代码 · 共 1,976 行 · 第 1/4 页

C
1,976
字号
/* *    Set the User Defined Part of the Display */static intcyber2000fb_set_var(struct fb_var_screeninfo *var, int con,		    struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	struct display *display;	struct par_info hw;	int err, chgvar;	/*	 * CONUPDATE and SMOOTH_XPAN are equal.  However,	 * SMOOTH_XPAN is only used internally by fbcon.	 */	if (var->vmode & FB_VMODE_CONUPDATE) {		var->vmode |= FB_VMODE_YWRAP;		var->xoffset = cfb->display->var.xoffset;		var->yoffset = cfb->display->var.yoffset;	}	err = cyber2000fb_decode_var(var, cfb, &hw);	if (err)		return err;	if (var->activate & FB_ACTIVATE_TEST)		return 0;	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)		return -EINVAL;	if (con < 0) {		display = cfb->fb.disp;	} else {		display = fb_display + con;	}	chgvar = cfb->fb.var.xres != var->xres ||		 cfb->fb.var.yres != var->yres ||		 cfb->fb.var.xres_virtual != var->xres_virtual ||		 cfb->fb.var.yres_virtual != var->yres_virtual ||		 cfb->fb.var.bits_per_pixel != var->bits_per_pixel;	if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) ||	    memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) ||	    memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue)))		chgvar = 1;	if (con < 0)		chgvar = 0;	/*	 * If we are setting all the virtual consoles, also set the	 * defaults used to create new consoles.	 */	err = var->activate;	var->activate = FB_ACTIVATE_NOW;	if (err & FB_ACTIVATE_ALL)		cfb->fb.disp->var = *var;	cfb->fb.var = *var;	cfb->fb.fix.line_length	= var->xres_virtual * var->bits_per_pixel / 8;	switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB8	case 8:	/* PSEUDOCOLOUR, 256 */		cfb->dispsw		= &fbcon_cfb8;		display->dispsw_data	= NULL;		break;#endif#ifdef FBCON_HAS_CFB16	case 16:/* DIRECTCOLOUR */		cfb->dispsw		= &fbcon_cfb16;		display->dispsw_data	= cfb->fb.pseudo_palette;		break;#endif#ifdef FBCON_HAS_CFB24	case 24:/* TRUECOLOUR, 16m */		cfb->dispsw		= &fbcon_cfb24;		display->dispsw_data	= cfb->fb.pseudo_palette;		break;#endif#ifdef FBCON_HAS_CFB32	case 32:/* TRUECOLOUR, 16m */		cfb->dispsw		= &fbcon_cfb32;		display->dispsw_data	= cfb->fb.pseudo_palette;		break;#endif	default:/* in theory this should never happen */		printk(KERN_WARNING "%s: no support for %dbpp\n",		       cfb->fb.fix.id, var->bits_per_pixel);		cfb->dispsw = &fbcon_dummy;		break;	}	/*	 * 8bpp displays are always pseudo colour.	 * 16bpp and above are direct colour or true colour, depending	 * on whether the RAMDAC palettes are bypassed.  (Direct colour	 * has palettes, true colour does not.)	 */	if (var->bits_per_pixel == 8)		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;	else if (hw.ramdac & RAMDAC_BYPASS)		cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;	else		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;	if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)		display->dispsw = &fbcon_cyber_accel;	else		display->dispsw = cfb->dispsw;	display->screen_base	= cfb->fb.screen_base;	display->line_length	= cfb->fb.fix.line_length;	display->next_line	= cfb->fb.fix.line_length;	display->visual		= cfb->fb.fix.visual;	display->type		= cfb->fb.fix.type;	display->type_aux	= cfb->fb.fix.type_aux;	display->ypanstep	= cfb->fb.fix.ypanstep;	display->ywrapstep	= cfb->fb.fix.ywrapstep;	display->can_soft_blank = 1;	display->inverse	= 0;	display->var		= *var;	cyber2000fb_set_timing(cfb, &hw);	cyber2000fb_update_start(cfb, var);	fb_set_cmap(&cfb->fb.cmap, 1, cyber2000fb_setcolreg, &cfb->fb);	if (chgvar && cfb->fb.changevar)		cfb->fb.changevar(con);	return 0;}/* *    Pan or Wrap the Display */static intcyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,			struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	u_int y_bottom;	y_bottom = var->yoffset;	if (!(var->vmode & FB_VMODE_YWRAP))		y_bottom += var->yres;	if (var->xoffset > (var->xres_virtual - var->xres))		return -EINVAL;	if (y_bottom > cfb->display->var.yres_virtual)		return -EINVAL;	if (cyber2000fb_update_start(cfb, var))		return -EINVAL;	cfb->display->var.xoffset = var->xoffset;	cfb->display->var.yoffset = var->yoffset;	if (var->vmode & FB_VMODE_YWRAP) {		cfb->display->var.vmode |= FB_VMODE_YWRAP;	} else {		cfb->display->var.vmode &= ~FB_VMODE_YWRAP;	}	return 0;}/* *    Update the `var' structure (called by fbcon.c) * *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. *    Since it's called by a kernel driver, no range checking is done. */static int cyber2000fb_updatevar(int con, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	return cyber2000fb_update_start(cfb, &fb_display[con].var);}static int cyber2000fb_switch(int con, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	struct display *display = cfb->display;	struct fb_cmap *cmap;	if (display) {		/*		 * Save the old colormap and video mode.		 */		if (display->cmap.len)			fb_copy_cmap(&cfb->fb.cmap, &display->cmap, 0);	}	cfb->display = display = fb_display + con;	/*	 * Install the new colormap and change the video mode.  By default,	 * fbcon sets all the colormaps and video modes to the default	 * values at bootup.	 *	 * Really, we want to set the colourmap size depending on the	 * depth of the new video mode.  For now, we leave it at its	 * default 256 entry.	 */	if (display->cmap.len)		cmap = &display->cmap;	else		cmap = fb_default_cmap(1 << display->var.bits_per_pixel);	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);	display->var.activate = FB_ACTIVATE_NOW;	cyber2000fb_set_var(&display->var, con, &cfb->fb);	return 0;}/* *    (Un)Blank the display. * *  Blank the screen if blank_mode != 0, else unblank. If *  blank == NULL then the caller blanks by setting the CLUT *  (Color Look Up Table) to all black. Return 0 if blanking *  succeeded, != 0 if un-/blanking failed due to e.g. a *  video mode which doesn't support it. Implements VESA *  suspend and powerdown modes on hardware that supports *  disabling hsync/vsync: *    blank_mode == 2: suspend vsync *    blank_mode == 3: suspend hsync *    blank_mode == 4: powerdown * *  wms...Enable VESA DMPS compatible powerdown mode *  run "setterm -powersave powerdown" to take advantage */static void cyber2000fb_blank(int blank, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	unsigned int sync = 0;	int i;	switch (blank) {	case 4:	/* powerdown - both sync lines down */		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;		break;		case 3:	/* hsync off */		sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;		break;		case 2:	/* vsync off */		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;		break;	case 1:	/* soft blank */	default: /* unblank */		break;	}	cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);	if (blank <= 1) {		/* turn on ramdacs */		cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN);		cyber2000fb_write_ramdac_ctrl(cfb);	}	/*	 * Soft blank/unblank the display.	 */	if (blank) {	/* soft blank */		for (i = 0; i < NR_PALETTE; i++) {			cyber2000fb_writeb(i, 0x3c8, cfb);			cyber2000fb_writeb(0, 0x3c9, cfb);			cyber2000fb_writeb(0, 0x3c9, cfb);			cyber2000fb_writeb(0, 0x3c9, cfb);		}	} else {	/* unblank */		for (i = 0; i < NR_PALETTE; i++) {			cyber2000fb_writeb(i, 0x3c8, cfb);			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);		}	}	if (blank >= 2) {		/* turn off ramdacs */		cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN;		cyber2000fb_write_ramdac_ctrl(cfb);	}}/* * Get the currently displayed virtual consoles colormap. */static intgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){	fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);	return 0;}/* * Get the currently displayed virtual consoles fixed part of the display. */static intgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){	*fix = info->fix;	return 0;}/* * Get the current user defined part of the display. */static intgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){	*var = info->var;	return 0;}static struct fb_ops cyber2000fb_ops = {	.owner		= THIS_MODULE,	.fb_set_var	= cyber2000fb_set_var,	.fb_set_cmap	= cyber2000fb_set_cmap,	.fb_pan_display	= cyber2000fb_pan_display,	.fb_get_fix	= gen_get_fix,	.fb_get_var	= gen_get_var,	.fb_get_cmap	= gen_get_cmap,};/* * This is the only "static" reference to the internal data structures * of this driver.  It is here solely at the moment to support the other * CyberPro modules external to this driver. */static struct cfb_info		*int_cfb_info;/* * Enable access to the extended registers */void cyber2000fb_enable_extregs(struct cfb_info *cfb){	cfb->func_use_count += 1;	if (cfb->func_use_count == 1) {		int old;		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);		old |= EXT_FUNC_CTL_EXTREGENBL;		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);	}}/* * Disable access to the extended registers */void cyber2000fb_disable_extregs(struct cfb_info *cfb){	if (cfb->func_use_count == 1) {		int old;		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);		old &= ~EXT_FUNC_CTL_EXTREGENBL;		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);	}	if (cfb->func_use_count == 0)		printk(KERN_ERR "disable_extregs: count = 0\n");	else		cfb->func_use_count -= 1;}void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var){	memcpy(var, &cfb->display->var, sizeof(struct fb_var_screeninfo));}/* * Attach a capture/tv driver to the core CyberX0X0 driver. */int cyber2000fb_attach(struct cyberpro_info *info, int idx){	if (int_cfb_info != NULL) {		info->dev	      = int_cfb_info->dev;		info->regs	      = int_cfb_info->regs;		info->fb	      = int_cfb_info->fb.screen_base;		info->fb_size	      = int_cfb_info->fb.fix.smem_len;		info->enable_extregs  = cyber2000fb_enable_extregs;		info->disable_extregs = cyber2000fb_disable_extregs;		info->info            = int_cfb_info;		strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));		MOD_INC_USE_COUNT;	}	return int_cfb_info != NULL;}/* * Detach a capture/tv driver from the core CyberX0X0 driver. */void cyber2000fb_detach(int idx){	MOD_DEC_USE_COUNT;}EXPORT_SYMBOL(cyber2000fb_attach);EXPORT_SYMBOL(cyber2000fb_detach);EXPORT_SYMBOL(cyber2000fb_enable_extregs);EXPORT_SYMBOL(cyber2000fb_disable_extregs);EXPORT_SYMBOL(cyber2000fb_get_fb_var);/* * These parameters give * 640x480, hsync 31.5kHz, vsync 60Hz */static struct fb_videomode __devinitdata cyber2000fb_default_mode = {	.refresh	= 60,	.xres		= 640,	.yres		= 480,	.pixclock	= 39722,	.left_margin	= 56,	.right_margin	= 16,	.upper_margin	= 34,	.lower_margin	= 9,	.hsync_len	= 88,	.vsync_len	= 2,	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,	.vmode		= FB_VMODE_NONINTERLACED};/* static register programming for all chips */static char igs_regs[] __devinitdata = {	EXT_CRT_IRQ,		0,	EXT_CRT_TEST,		0,	EXT_SYNC_CTL,		0,	EXT_SEG_WRITE_PTR,	0,	EXT_SEG_READ_PTR,	0,	EXT_BIU_MISC,		EXT_BIU_MISC_LIN_ENABLE |				EXT_BIU_MISC_COP_ENABLE |				EXT_BIU_MISC_COP_BFC,	EXT_FUNC_CTL,		0,	CURS_H_START,		0,	CURS_H_START + 1,	0,	CURS_H_PRESET,		0,	CURS_V_START,		0,	CURS_V_START + 1,	0,	CURS_V_PRESET,		0,	CURS_CTL,		0,	EXT_ATTRIB_CTL,		EXT_ATTRIB_CTL_EXT,	EXT_OVERSCAN_RED,	0,	EXT_OVERSCAN_GREEN,	0,	EXT_OVERSCAN_BLUE,	0,};/* specific register setting for the 2000 series */static char igs_2000_regs[] __devinitdata = {	/* some of these are questionable when we have a BIOS */	EXT_MEM_CTL0,		EXT_MEM_CTL0_7CLK |				EXT_MEM_CTL0_RAS_1 |				EXT_MEM_CTL0_MULTCAS,	EXT_HIDDEN_CTL1,	0x30,	EXT_FIFO_CTL,		0x0b,	EXT_FIFO_CTL + 1,	0x17,	0x76,			0x00,	EXT_HIDDEN_CTL4,	0xc8};/* * Initialise the CyberPro hardware. */static void cyberpro_init_hw(struct cfb_info *cfb){	int i;	for (i = 0; i < sizeof(igs_regs); i += 2)		cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);	if (cfb->id == ID_CYBERPRO_5000) {		/*		 * On the CyberPro5XXXX, ensure that we're using the correct		 * PLL (5XXX's may be programmed to use an additional set of		 * PLLs.)		 */		unsigned char val;		cyber2000fb_writeb(0xba, 0x3ce, cfb);		val = cyber2000fb_readb(0x3cf, cfb) & 0x80;		cyber2000fb_writeb(val, 0x3cf, cfb);

⌨️ 快捷键说明

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