ep93xxfb.c

来自「非常珍贵的LINUX下的专门针对CIRRUS公司的EP93XX平台的驱动源代码」· C语言 代码 · 共 2,214 行 · 第 1/4 页

C
2,214
字号
}#ifdef CONFIG_EP93XX_GRAPHICS#ifdef CONFIG_FB_EP93XX_8BPP#define BITS_PER_PIXEL 8#define BYTES_PER_PIXEL 1#define PIXEL_MASK 3#define PIXEL_SHIFT 2#define PIXEL_FORMAT 0x00040000#endif#ifdef CONFIG_FB_EP93XX_16BPP_565#define BITS_PER_PIXEL 16#define BYTES_PER_PIXEL 2#define PIXEL_MASK 1#define PIXEL_SHIFT 1#define PIXEL_FORMAT 0x00080000#endif#define BYTES_PER_LINE (fb_info.var.xres * BYTES_PER_PIXEL)static DECLARE_WAIT_QUEUE_HEAD(ep93xxfb_wait_in);static voidep93xxfb_irq_handler(int i, void *blah, struct pt_regs *regs){	outl(0x00000000, BLOCKCTRL);	wake_up_interruptible(&ep93xxfb_wait_in);}static voidep93xxfb_wait(void){	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(&ep93xxfb_wait_in, &wait);	current->state = TASK_INTERRUPTIBLE;	while (inl(BLOCKCTRL) & 0x00000001) {		schedule();		current->state = TASK_INTERRUPTIBLE;	}	remove_wait_queue(&ep93xxfb_wait_in, &wait);	current->state = TASK_RUNNING;}static unsigned char pucBlitBuf[4096];static intep93xxfb_blit(struct ep93xx_blit *blit){	unsigned long value = 0, size, dx1, dx2, dy1, sx1, sx2, sy1;	if ((blit->dx >= fb_info.var.xres) ||	    (blit->dy >= fb_info.var.yres) ||	    ((blit->dx + blit->width - 1) >= fb_info.var.xres) ||	    ((blit->dy + blit->height - 1) >= fb_info.var.yres))		return -EFAULT;	value = blit->flags & (BLIT_TRANSPARENT | BLIT_MASK_MASK |			       BLIT_DEST_MASK | BLIT_1BPP_SOURCE);	if ((blit->flags & BLIT_SOURCE_MASK) == BLIT_SOURCE_MEMORY) {		if (blit->flags & BLIT_1BPP_SOURCE) {			size = blit->swidth * blit->height / 8;			if (size <= 4096)				copy_from_user(pucBlitBuf, blit->data, size);			else {				for (size = blit->height; size; ) {					blit->height = 32768 / blit->swidth;					if (blit->height > size)						blit->height = size;					ep93xxfb_blit(blit);					blit->dy += blit->height;					blit->data += blit->swidth *						      blit->height / 8;					size -= blit->height;				}				return 0;			}			if (blit->flags & BLIT_TRANSPARENT)				value ^= 0x00004000;			outl(0x00000007, SRCPIXELSTRT);			outl(blit->swidth >> 5, SRCLINELENGTH);			outl((blit->width - 1) >> 5, BLKSRCWIDTH);			outl(blit->bgcolor, BACKGROUND);		} else {			size = blit->swidth * blit->height * BYTES_PER_PIXEL;			if (size <= 4096)				copy_from_user(pucBlitBuf, blit->data, size);			else {				for (size = blit->height; size; ) {					blit->height = 4096 / BYTES_PER_PIXEL /						       blit->swidth;					if (blit->height > size)						blit->height = size;					ep93xxfb_blit(blit);					blit->dy += blit->height;					blit->data += blit->swidth *						      blit->height *						      BYTES_PER_PIXEL;					size -= blit->height;				}				return 0;			}			outl(0x00000000, SRCPIXELSTRT);			outl(blit->swidth >> PIXEL_SHIFT, SRCLINELENGTH);			outl((blit->width - 1) >> PIXEL_SHIFT, BLKSRCWIDTH);		}		outl(virt_to_phys(pucBlitBuf), BLKSRCSTRT);		dx1 = blit->dx;		dy1 = blit->dy;		dx2 = blit->dx + blit->width - 1;	} else {		if ((blit->sx >= fb_info.var.xres) ||		    (blit->sy >= fb_info.var.yres) ||		    ((blit->sx + blit->width - 1) >= fb_info.var.xres) ||		    ((blit->sy + blit->height - 1) >= fb_info.var.yres))			return -EFAULT;		if ((blit->dy == blit->sy) && (blit->dx == blit->sx))			return 0;		if ((blit->dy == blit->sy) &&		    (blit->dx > blit->sx) &&		    (blit->dx < (blit->sx + blit->width - 1))) {			dx1 = blit->dx + blit->width - 1;			dx2 = blit->dx;			sx1 = blit->sx + blit->width - 1;			sx2 = blit->sx;			value |= 0x000000a0;		} else {			dx1 = blit->dx;			dx2 = blit->dx + blit->width - 1;			sx1 = blit->sx;			sx2 = blit->sx + blit->width - 1;		}		if (blit->dy <= blit->sy) {			dy1 = blit->dy;			sy1 = blit->sy;		} else {			dy1 = blit->dy + blit->height - 1;			sy1 = blit->sy + blit->height - 1;			value |= 0x00000140;		}		outl(((sx1 & PIXEL_MASK) * BITS_PER_PIXEL) |		     (((sx2 & PIXEL_MASK) * BITS_PER_PIXEL) << 16),		     SRCPIXELSTRT);		outl(inl(VIDSCRNPAGE) + (sy1 * BYTES_PER_LINE) +		     ((sx1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKSRCSTRT);		outl(BYTES_PER_LINE / 4, SRCLINELENGTH);		if (sx1 < sx2)			outl((sx2 >> PIXEL_SHIFT) - (sx1 >> PIXEL_SHIFT),			     BLKSRCWIDTH);		else			outl((sx1 >> PIXEL_SHIFT) - (sx2 >> PIXEL_SHIFT),			     BLKSRCWIDTH);	}	outl(((dx1 & PIXEL_MASK) * BITS_PER_PIXEL) |	     (((dx2 & PIXEL_MASK) * BITS_PER_PIXEL) << 16), DESTPIXELSTRT);	outl(inl(VIDSCRNPAGE) + (dy1 * BYTES_PER_LINE) +	     ((dx1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT);	outl(BYTES_PER_LINE / 4, DESTLINELENGTH);	if (dx1 < dx2)		outl((dx2 >> PIXEL_SHIFT) - (dx1 >> PIXEL_SHIFT),		     BLKDESTWIDTH);	else		outl((dx1 >> PIXEL_SHIFT) - (dx2 >> PIXEL_SHIFT),		     BLKDESTWIDTH);	outl(blit->height - 1, BLKDESTHEIGHT);	outl(blit->fgcolor, BLOCKMASK);	outl(blit->transcolor, TRANSPATTRN);	outl(value | PIXEL_FORMAT | 0x00000003, BLOCKCTRL);	ep93xxfb_wait();	return 0;}static intep93xxfb_fill(struct ep93xx_fill *fill){	if ((fill->dx >= fb_info.var.xres) ||	    (fill->dy >= fb_info.var.yres))		return -EFAULT;	if ((fill->dx + fill->width - 1) >= fb_info.var.xres)		fill->width = fb_info.var.xres - fill->dx;	if ((fill->dy + fill->height - 1) >= fb_info.var.yres)		fill->height = fb_info.var.yres - fill->dy;	outl(mypar.p_screen_base + (fill->dy * BYTES_PER_LINE) +	     ((fill->dx * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT);	outl(((fill->dx & PIXEL_MASK) * BITS_PER_PIXEL) |	     ((((fill->dx + fill->width - 1) & PIXEL_MASK) *	       BITS_PER_PIXEL) << 16), DESTPIXELSTRT);	outl(BYTES_PER_LINE / 4, DESTLINELENGTH);	outl(((fill->dx + fill->width - 1) >> PIXEL_SHIFT) -	     (fill->dx >> PIXEL_SHIFT), BLKDESTWIDTH);	outl(fill->height - 1, BLKDESTHEIGHT);	outl(fill->color, BLOCKMASK);	outl(PIXEL_FORMAT | 0x0000000b, BLOCKCTRL);	ep93xxfb_wait();	return 0;}static unsigned longisqrt(unsigned long a){	unsigned long rem = 0;	unsigned long root = 0;	int i;	for (i = 0; i < 16; i++) {		root <<= 1;		rem = ((rem << 2) + (a >> 30));		a <<= 2;		root++;		if (root <= rem) {			rem -= root;			root++;		} else			root--;	}	return root >> 1;}static intep93xxfb_line(struct ep93xx_line *line){	unsigned long value = 0;	long dx, dy, count, xinc, yinc, xval, yval, incr;	if ((line->x1 >= fb_info.var.xres) ||	    (line->x2 >= fb_info.var.xres) ||	    (line->y1 >= fb_info.var.yres) ||	    (line->y2 >= fb_info.var.yres))		return -EFAULT;	dx = line->x2 - line->x1;	if (dx < 0) {		value |= 0x00000020;		dx *= -1;	}	dy = line->y2 - line->y1;	if (dy < 0) {		value |= 0x00000040;		dy *= -1;	}	if (line->flags & LINE_PRECISE) {		count = isqrt(((dy * dy) + (dx * dx)) * 4096);		xinc = (4095 * 64 * dx) / count;		yinc = (4095 * 64 * dy) / count;		xval = 2048;		yval = 2048;		count = 0;		while (dx || dy) {			incr = 0;			xval -= xinc;			if (xval <= 0) {				xval += 4096;				dx--;				incr = 1;			}			yval -= yinc;			if (yval <= 0) {				yval += 4096;				dy--;				incr = 1;			}			count += incr;		}	} else {		if (dx == dy) {			xinc = 4095;			yinc = 4095;			count = dx;		} else if (dx < dy) {			xinc = (dx * 4095) / dy;			yinc = 4095;			count = dy;		} else {			xinc = 4095;			yinc = (dy * 4095) / dx;			count = dx;		}	}	outl(0x08000800, LINEINIT);	if (line->flags & LINE_PATTERN)		outl(line->pattern, LINEPATTRN);	else		outl(0x000fffff, LINEPATTRN);	outl(mypar.p_screen_base + (line->y1 * BYTES_PER_LINE) +	     ((line->x1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT);	outl(((line->x1 & PIXEL_MASK) * BITS_PER_PIXEL) |	     ((((line->x1 + dx - 1) & PIXEL_MASK) *	       BITS_PER_PIXEL) << 16), DESTPIXELSTRT);	outl(BYTES_PER_LINE / 4, DESTLINELENGTH);	outl(line->fgcolor, BLOCKMASK);	outl(line->bgcolor, BACKGROUND);	outl((yinc << 16) | xinc, LINEINC);	outl(count & 0xfff, BLKDESTWIDTH);	outl(0, BLKDESTHEIGHT);	value |= (line->flags & LINE_BACKGROUND) ? 0x00004000 : 0;	outl(value | PIXEL_FORMAT | 0x00000013, BLOCKCTRL);	ep93xxfb_wait();	return 0;}#endifstatic intep93xxfb_ioctl(struct inode *inode, struct file *file,	       unsigned int cmd, unsigned long arg, int con,	       struct fb_info *info){	struct ep93xx_cursor cursor;	struct ep93xx_blit blit;	struct ep93xx_fill fill;	struct ep93xx_line line;	unsigned long caps;	switch (cmd) {	case FBIO_EP93XX_GET_CAPS:		caps = EP93XX_CAP_CURSOR;#ifdef CONFIG_EP93XX_GRAPHICS		caps |= EP93XX_CAP_LINE | EP93XX_CAP_FILL | EP93XX_CAP_BLIT;#endif		copy_to_user((void *)arg, &caps, sizeof(unsigned long));		return 0;	case FBIO_EP93XX_CURSOR:		copy_from_user(&cursor, (void *)arg,			       sizeof(struct ep93xx_cursor));		ep93xxfb_cursor(&cursor);		return 0;#ifdef CONFIG_EP93XX_GRAPHICS	case FBIO_EP93XX_LINE:		copy_from_user(&line, (void *)arg, sizeof(struct ep93xx_line));		return ep93xxfb_line(&line);	case FBIO_EP93XX_FILL:		copy_from_user(&fill, (void *)arg, sizeof(struct ep93xx_fill));		return ep93xxfb_fill(&fill);	case FBIO_EP93XX_BLIT:		copy_from_user(&blit, (void *)arg, sizeof(struct ep93xx_blit));		return ep93xxfb_blit(&blit);#endif	default:		return -EFAULT;	}}//=============================================================================// CheckAdjustVar//=============================================================================// Check and adjust the video params in 'var'. If a value doesn't fit, round it// up, if it's too big, return -EINVAL.//// Suggestion: Round up in the following order: bits_per_pixel, xres, yres,// xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,// horizontal timing, vertical timing.//// Note: This is similar to generic fb call sequence//    (decode_var, set_par, decode_var)// in that var gets fixed if fixable and error if not.  The translating// to parameter settings is handled inside activate_var below.//=============================================================================static int CheckAdjustVar(struct fb_var_screeninfo *var){	DPRINTK("Entering\n");	//	// Just set virtual to actual resolution.	//	var->xres_virtual = mypar.xres;	var->yres_virtual = mypar.yres;	DPRINTK("check: var->bpp=%d\n", var->bits_per_pixel);	switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4	case 4:					//TBD need to adjust var		break;#endif#ifdef FBCON_HAS_CFB8	case 8:		/* through palette */		var->red.length	= 4;	//TBD is this used? should be 8?		//TBD what about offset?		var->green	= var->red;		var->blue	= var->red;		var->transp.length = 0;		break;#endif#ifdef FBCON_HAS_CFB16	case 16:  	/* RGB 565 */		var->red.length    = 5;		var->blue.length   = 5;		var->green.length  = 6;		var->transp.length = 0;		var->red.offset    = 11;		var->green.offset  = 5;		var->blue.offset   = 0;		var->transp.offset = 0;		break;#endif	default:		DPRINTK("Invalid var->bits_per_pixel = %d\n",var->bits_per_pixel);		return -EINVAL;	}	return 0;}////	Entry:	con	valid console number//			or -1 to indicate current console//			(note: current console maybe default initially)////		var	pointer to var structure already allocated by caller.////	Action: Set pointed at var structure to fb_display[con].var or current.////	Exit:	none////	Note:	This function called by fb_mem.c,static intep93xxfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){	//TBD I do not expect call with con=-1	//TBD Maybe I do not really need to support this??	if (con == -1)		DPRINTK("get_var called with con=-1\n");	DPRINTK("con=%d\n", con);	if (con == -1) {		//TBD need to set var with current settings.		//TBD why can't we just take copy it from info??		//ep93xxfb_get_par(&par);		//ep93xxfb_encode_var(var, &par);		//TBD for now current settings is always equal to		//TBD default display settings		//TBD Is this really complete?		*var = global_disp.var;		// copies structure	} else		*var = fb_display[con].var;	// copies structure	return 0;}/* * ep93xxfb_set_var(): * *	Entry:	con 	-1 means set default display *			else set fb_display[con] * *		var	static var structure to define video mode * *	Action:	Settings are tweaked to get a usable display mode. *		Set console display values for specified console, *		if console valid.  Else set default display values. * *	Exit:	Returns error if cannot tweak settings to usable mode. */static intep93xxfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){	struct display *display;	int err, chgvar = 0;	if (con == -1)		DPRINTK("called with con=-1\n");	//	// Display is not passed in, but we alter as side-effect	//	if (con >= 0)		//		// Display settings for console		//		display = &fb_display[con];	else		//		// Set default display settings		//		display = &global_disp;	//	// Check and adjust var if need be to get usable display mode, else return	// error if impossible to adjust	//	if ((err = CheckAdjustVar(var)))		return err;	//  Update parameters	DPRINTK("check: var->bpp=%d\n", var->bits_per_pixel);	switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4	case 4:		mypar.visual = FB_VISUAL_PSEUDOCOLOR;		mypar.palette_size = 16;		break;#endif#ifdef FBCON_HAS_CFB8	case 8:		mypar.visual = FB_VISUAL_PSEUDOCOLOR;		mypar.palette_size = 256;		break;#endif#ifdef FBCON_HAS_CFB16	case 16:		mypar.visual = FB_VISUAL_TRUECOLOR;		mypar.palette_size = 16;		break;#endif	default:		DPRINTK("ERROR! Bad bpp %d\n", var->bits_per_pixel);		return -EINVAL;	}	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)		return 0;	else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) &&			 ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))		return -EINVAL;	if (con >= 0)		if ((display->var.xres != var->xres) ||		    (display->var.yres != var->yres) ||		    (display->var.xres_virtual != var->xres_virtual) ||		    (display->var.yres_virtual != var->yres_virtual) ||		    (display->var.sync != var->sync) ||		    (display->var.bits_per_pixel != var->bits_per_pixel) ||		    (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||		    (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||		    (memcmp(&display->var.blue, &var->blue, sizeof(var->blue))))			chgvar = 1;	DPRINTK("display->var.xres %d\n",display->var.xres);	DPRINTK("display->var.yres %d\n",display->var.yres);	DPRINTK("display->var.xres_virtual %d\n",display->var.xres_virtual);	DPRINTK("display->var.yres_virtual %d\n",display->var.yres_virtual);	//TBD is this complete?	display->var = *var;	// copies structure	display->screen_base = mypar.v_screen_base;	display->visual	= mypar.visual;	display->type = FB_TYPE_PACKED_PIXELS;

⌨️ 快捷键说明

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