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

📄 cirrusfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."			"color depth not supported.\n",			var->xres, var->yres, var->bits_per_pixel);		DPRINTK("EXIT - EINVAL error\n");		return -EINVAL;	}	if (var->xres_virtual < var->xres)		var->xres_virtual = var->xres;	/* use highest possible virtual resolution */	if (var->yres_virtual == -1) {		var->yres_virtual = pixels / var->xres_virtual;		printk(KERN_INFO "cirrusfb: virtual resolution set to "			"maximum of %dx%d\n", var->xres_virtual,			var->yres_virtual);	}	if (var->yres_virtual < var->yres)		var->yres_virtual = var->yres;	if (var->xres_virtual * var->yres_virtual > pixels) {		printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "		      "virtual resolution too high to fit into video memory!\n",			var->xres_virtual, var->yres_virtual,			var->bits_per_pixel);		DPRINTK("EXIT - EINVAL error\n");		return -EINVAL;	}	if (var->xoffset < 0)		var->xoffset = 0;	if (var->yoffset < 0)		var->yoffset = 0;	/* truncate xoffset and yoffset 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;	switch (var->bits_per_pixel) {	case 1:		var->red.offset = 0;		var->red.length = 1;		var->green = var->red;		var->blue = var->red;		break;	case 8:		var->red.offset = 0;		var->red.length = 6;		var->green = var->red;		var->blue = var->red;		break;	case 16:		if (isPReP) {			var->red.offset = 2;			var->green.offset = -3;			var->blue.offset = 8;		} else {			var->red.offset = 10;			var->green.offset = 5;			var->blue.offset = 0;		}		var->red.length = 5;		var->green.length = 5;		var->blue.length = 5;		break;	case 32:		if (isPReP) {			var->red.offset = 8;			var->green.offset = 16;			var->blue.offset = 24;		} else {			var->red.offset = 16;			var->green.offset = 8;			var->blue.offset = 0;		}		var->red.length = 8;		var->green.length = 8;		var->blue.length = 8;		break;	default:		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);		assert(false);		/* should never occur */		break;	}	var->red.msb_right =	    var->green.msb_right =	    var->blue.msb_right =	    var->transp.offset =	    var->transp.length =	    var->transp.msb_right = 0;	yres = var->yres;	if (var->vmode & FB_VMODE_DOUBLE)		yres *= 2;	else if (var->vmode & FB_VMODE_INTERLACED)		yres = (yres + 1) / 2;	if (yres >= 1280) {		printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "			"special treatment required! (TODO)\n");		DPRINTK("EXIT - EINVAL error\n");		return -EINVAL;	}	return 0;}static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,				struct cirrusfb_regs *regs,				struct fb_info *info){	long freq;	long maxclock;	int maxclockidx = var->bits_per_pixel >> 3;	struct cirrusfb_info *cinfo = info->par;	switch (var->bits_per_pixel) {	case 1:		info->fix.line_length = var->xres_virtual / 8;		info->fix.visual = FB_VISUAL_MONO10;		break;	case 8:		info->fix.line_length = var->xres_virtual;		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;		break;	case 16:	case 32:		info->fix.line_length = var->xres_virtual * maxclockidx;		info->fix.visual = FB_VISUAL_TRUECOLOR;		break;	default:		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);		assert(false);		/* should never occur */		break;	}	info->fix.type = FB_TYPE_PACKED_PIXELS;	/* convert from ps to kHz */	freq = PICOS2KHZ(var->pixclock);	DPRINTK("desired pixclock: %ld kHz\n", freq);	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];	regs->multiplexing = 0;	/* If the frequency is greater than we can support, we might be able	 * to use multiplexing for the video mode */	if (freq > maxclock) {		switch (cinfo->btype) {		case BT_ALPINE:		case BT_GD5480:			regs->multiplexing = 1;			break;		default:			printk(KERN_ERR "cirrusfb: Frequency greater "				"than maxclock (%ld kHz)\n", maxclock);			DPRINTK("EXIT - return -EINVAL\n");			return -EINVAL;		}	}#if 0	/* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where	 * the VCLK is double the pixel clock. */	switch (var->bits_per_pixel) {	case 16:	case 32:		if (var->xres <= 800)			/* Xbh has this type of clock for 32-bit */			freq /= 2;		break;	}#endif	return 0;}static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo,					int div){	unsigned char old1f, old1e;	assert(cinfo != NULL);	old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;	if (div) {		DPRINTK("Set %s as pixclock source.\n",					(div == 2) ? "MCLK/2" : "MCLK");		old1f |= 0x40;		old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;		if (div == 2)			old1e |= 1;		vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);	}	vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);}/*************************************************************************	cirrusfb_set_par_foo()	actually writes the values for a new video mode into the hardware,**************************************************************************/static int cirrusfb_set_par_foo(struct fb_info *info){	struct cirrusfb_info *cinfo = info->par;	struct fb_var_screeninfo *var = &info->var;	struct cirrusfb_regs regs;	u8 __iomem *regbase = cinfo->regbase;	unsigned char tmp;	int offset = 0, err;	const struct cirrusfb_board_info_rec *bi;	int hdispend, hsyncstart, hsyncend, htotal;	int yres, vdispend, vsyncstart, vsyncend, vtotal;	long freq;	int nom, den, div;	DPRINTK("ENTER\n");	DPRINTK("Requested mode: %dx%dx%d\n",	       var->xres, var->yres, var->bits_per_pixel);	DPRINTK("pixclock: %d\n", var->pixclock);	init_vgachip(info);	err = cirrusfb_decode_var(var, &regs, info);	if (err) {		/* should never happen */		DPRINTK("mode change aborted.  invalid var.\n");		return -EINVAL;	}	bi = &cirrusfb_board_info[cinfo->btype];	hsyncstart = var->xres + var->right_margin;	hsyncend = hsyncstart + var->hsync_len;	htotal = (hsyncend + var->left_margin) / 8 - 5;	hdispend = var->xres / 8 - 1;	hsyncstart = hsyncstart / 8 + 1;	hsyncend = hsyncend / 8 + 1;	yres = var->yres;	vsyncstart = yres + var->lower_margin;	vsyncend = vsyncstart + var->vsync_len;	vtotal = vsyncend + var->upper_margin;	vdispend = yres - 1;	if (var->vmode & FB_VMODE_DOUBLE) {		yres *= 2;		vsyncstart *= 2;		vsyncend *= 2;		vtotal *= 2;	} else if (var->vmode & FB_VMODE_INTERLACED) {		yres = (yres + 1) / 2;		vsyncstart = (vsyncstart + 1) / 2;		vsyncend = (vsyncend + 1) / 2;		vtotal = (vtotal + 1) / 2;	}	vtotal -= 2;	vsyncstart -= 1;	vsyncend -= 1;	if (yres >= 1024) {		vtotal /= 2;		vsyncstart /= 2;		vsyncend /= 2;		vdispend /= 2;	}	if (regs.multiplexing) {		htotal /= 2;		hsyncstart /= 2;		hsyncend /= 2;		hdispend /= 2;	}	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */	/* if debugging is enabled, all parameters get output before writing */	DPRINTK("CRT0: %d\n", htotal);	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);	DPRINTK("CRT1: %d\n", hdispend);	vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);	DPRINTK("CRT2: %d\n", var->xres / 8);	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);	/*  + 128: Compatible read */	DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32);	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,		 128 + ((htotal + 5) % 32));	DPRINTK("CRT4: %d\n", hsyncstart);	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);	tmp = hsyncend % 32;	if ((htotal + 5) & 32)		tmp += 128;	DPRINTK("CRT5: %d\n", tmp);	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);	DPRINTK("CRT6: %d\n", vtotal & 0xff);	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);	tmp = 16;		/* LineCompare bit #9 */	if (vtotal & 256)		tmp |= 1;	if (vdispend & 256)		tmp |= 2;	if (vsyncstart & 256)		tmp |= 4;	if ((vdispend + 1) & 256)		tmp |= 8;	if (vtotal & 512)		tmp |= 32;	if (vdispend & 512)		tmp |= 64;	if (vsyncstart & 512)		tmp |= 128;	DPRINTK("CRT7: %d\n", tmp);	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);	tmp = 0x40;		/* LineCompare bit #8 */	if ((vdispend + 1) & 512)		tmp |= 0x20;	if (var->vmode & FB_VMODE_DOUBLE)		tmp |= 0x80;	DPRINTK("CRT9: %d\n", tmp);	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);	DPRINTK("CRT10: %d\n", vsyncstart & 0xff);	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);	DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16);	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);	DPRINTK("CRT12: %d\n", vdispend & 0xff);	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);	DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff);	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);	DPRINTK("CRT16: %d\n", vtotal & 0xff);	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);	DPRINTK("CRT18: 0xff\n");	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);	tmp = 0;	if (var->vmode & FB_VMODE_INTERLACED)		tmp |= 1;	if ((htotal + 5) & 64)		tmp |= 16;	if ((htotal + 5) & 128)		tmp |= 32;	if (vtotal & 256)		tmp |= 64;	if (vtotal & 512)		tmp |= 128;	DPRINTK("CRT1a: %d\n", tmp);	vga_wcrt(regbase, CL_CRT1A, tmp);	freq = PICOS2KHZ(var->pixclock);	bestclock(freq, &nom, &den, &div);	/* set VCLK0 */	/* hardware RefClock: 14.31818 MHz */	/* formula: VClk = (OSC * N) / (D * (1+P)) */	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */	if (cinfo->btype == BT_ALPINE) {		/* if freq is close to mclk or mclk/2 select mclk		 * as clock source		 */		int divMCLK = cirrusfb_check_mclk(cinfo, freq);		if (divMCLK)  {			nom = 0;			cirrusfb_set_mclk_as_source(cinfo, divMCLK);		}	}	if (nom) {		vga_wseq(regbase, CL_SEQRB, nom);		tmp = den << 1;		if (div != 0)			tmp |= 1;		/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */		if ((cinfo->btype == BT_SD64) ||		    (cinfo->btype == BT_ALPINE) ||		    (cinfo->btype == BT_GD5480))			tmp |= 0x80;		DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);		vga_wseq(regbase, CL_SEQR1B, tmp);	}	if (yres >= 1024)		/* 1280x1024 */		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);	else		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit		 * address wrap, no compat. */		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);/* HAEH?	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */	/* don't know if it would hurt to also program this if no interlaced */	/* mode is used, but I feel better this way.. :-) */	if (var->vmode & FB_VMODE_INTERLACED)		vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);	else		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */	vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);	/* adjust horizontal/vertical sync type (low/high) */	/* enable display memory & CRTC I/O address for color mode */	tmp = 0x03;	if (var->sync & FB_SYNC_HOR_HIGH_ACT)		tmp |= 0x40;	if (var->sync & FB_SYNC_VERT_HIGH_ACT)		tmp |= 0x80;	WGen(cinfo, VGA_MIS_W, tmp);	/* Screen A Preset Row-Scan register */	vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);	/* text cursor on and start line */	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);	/* text cursor end line */	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);	/******************************************************	 *	 * 1 bpp	 *	 */	/* programming for different color depths */	if (var->bits_per_pixel == 1) {		DPRINTK("cirrusfb: preparing for 1 bit deep display\n");		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */		/* SR07 */		switch (cinfo->btype) {		case BT_SD64:		case BT_PICCOLO:		case BT_PICASSO:		case BT_SPECTRUM:		case BT_PICASSO4:		case BT_ALPINE:		case BT_GD5480:			DPRINTK(" (for GD54xx)\n");			vga_wseq(regbase, CL_SEQR7,				  regs.multiplexing ?					bi->sr07_1bpp_mux : bi->sr07_1bpp);			break;		case BT_LAGUNA:			DPRINTK(" (for GD546x)\n");			vga_wseq(regbase, CL_SEQR7,				vga_rseq(regbase, CL_SEQR7) & ~0x01);			break;		default:			printk(KERN_WARNING "cirrusfb: unknown Board\n");			break;		}		/* Extended Sequencer Mode */		switch (cinfo->btype) {		case BT_SD64:			/* setting the SEQRF on SD64 is not necessary			 * (only during init)			 */			DPRINTK("(for SD64)\n");			/*  MCLK select */			vga_wseq(regbase, CL_SEQR1F, 0x1a);			break;		case BT_PICCOLO:		case BT_SPECTRUM:			DPRINTK("(for Piccolo/Spectrum)\n");			/* ### ueberall 0x22? */			/* ##vorher 1c MCLK select */			vga_wseq(regbase, CL_SEQR1F, 0x22);			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */			vga_wseq(regbase, CL_SEQRF, 0xb0);

⌨️ 快捷键说明

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