omapfb_main.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,875 行 · 第 1/4 页

C
1,875
字号
	DBGLEAVE(1);	return 0;}/* Called when the omapfb device is closed. We make sure that any pending * gfx DMA operations are ended, before we return. */static int omapfb_release(struct fb_info *info, int user){	struct omapfb_device *dev = (struct omapfb_device *)info->par;	int sync = 0;	DBGENTER(1);	spin_lock_bh(&dev->gfx.spinlock);	if (dev->gfx.f_run)		sync = 1;	spin_unlock_bh(&dev->gfx.spinlock);	if (sync) {		gfxdma_sync(&dev->gfx);	}#ifdef OMAPFB_DBG_FIFO	{		int i;		for (i = 0; i < GFX_FIFO_SIZE; i++)			printk(KERN_INFO "f_run[%d]=%lu\n", i + 1,					stat.f_run[i]);	}#endif	DBGLEAVE(1);	return 0;}/* Store a single color palette entry into a pseudo palette or the hardware * palette if one is available. For now we support only 16bpp and thus store * the entry only to the pseudo palette. */static int omapfb_setcolreg(u_int regno, u_int red, u_int green,			    u_int blue, u_int transp,			    struct fb_info *info){	u16 pal;	int r = 0;	DBGENTER(2);	if (regno >= 16) {		r = -1;		goto exit;	}	pal = ((red >> 11) << 11) | ((green >> 10) << 5) | (blue >> 11);	((u32 *)(info->pseudo_palette))[regno] = pal;exit:	DBGLEAVE(2);	return r;}/* Blank the screen. Yet to be done. */static int omapfb_blank(int blank, struct fb_info *info){	DBGENTER(1);	DBGLEAVE(1);	return 0;}/* Setup a constant fill DMA transfer. Destination must be elem size aligned. */static inline void fill_block(struct omapfb_device *fbdev,			      unsigned long dst, unsigned long enumber,			      unsigned long height, int esize, u32 color){	unsigned long	fidx;	int		lch;	DBGPRINT(2, "dst:%#010x enumber:%d height:%d esize:%d color:%#010x\n",		 dst, enumber, height, esize, color);	fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1;	if (gfxdma_get_lch(&fbdev->gfx, &lch)) {		PRNERR("ioctl interrupted\n");		return;	}	gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height,			      0, OMAP_DMA_AMODE_CONSTANT,			      dst, OMAP_DMA_AMODE_DOUBLE_IDX);	gfxdma_set_lch_index(lch, 0, 0, 1, fidx);	gfxdma_set_lch_color(lch, color, OMAP_DMA_CONSTANT_FILL);	gfxdma_enqueue(&fbdev->gfx, lch);	DUMP_DMA_REGS(lch);}/* Fill the specified rectangle with a solid color. * ROP_XOR and bpp<8 is passed to the unaccelerated function as these cases * can't be handled by the DMA hardware. * When frame flipping is in effect use the destination frame. * We'll make our best to use the largest possible elem size, doing the fill * in more parts if alignment requires us to do so. */static void omapfb_fillrect(struct fb_info *fbi,			    const struct fb_fillrect *rect){	struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;	int		dx = rect->dx, dy = rect->dy;	int		vxres = fbi->var.xres_virtual;	int		vyres = fbi->var.yres_virtual;	int		width = rect->width, height = rect->height;	unsigned long	dst;	u32		color;	int		bpp;	int		enumber, esize;	DBGENTER(2);	bpp = fbi->var.bits_per_pixel;	/* bpp < 8 is tbd.	 * We can't do ROP_XOR with DMA	 * If IRQs are disabled we can't use DMA	 */	if (rect->rop == ROP_XOR || irqs_disabled()) {		cfb_fillrect(fbi, rect);		return;	}	/* Clipping */	if (!width || !height || dx > vxres || dy > vyres)		return;	if (dx + width > vxres)		width = vxres - dx;	if (dy + height > vyres)		height = vyres - dy;	if (bpp == 12)		bpp = 16;	width = width * bpp / 8;	dst = fbdev->lcddma_handle + fbdev->dst_frame_org;	dst += dx * bpp / 8 + dy * fbi->fix.line_length;	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR ||	    fbi->fix.visual == FB_VISUAL_DIRECTCOLOR )		color = ((u32 *) (fbi->pseudo_palette))[rect->color];	else		color = rect->color;	switch (bpp) {	case 8:		color |= color << 8;		/* Fall through */	case 16:		color |= color << 16;	}	if ((dst & 3) || width < 4) {		if (!(dst & 1) && width > 1) {			esize = 2;			enumber = 1;			width -= 2;		} else {			esize = 1;			enumber = 4 - (esize & 3);			if (enumber > width)				enumber = width;			width -= enumber;		}		fill_block(fbdev, dst, enumber, height, esize, color);		dst = (dst + 3) & ~3;	}	if (width) {		enumber = width / 4;		fill_block(fbdev, dst, enumber, height, 4, color);		dst += enumber * 4;		width -= enumber * 4;	}	if (width) {		if (width == 2) {			esize = 2;			enumber = 1;		} else {			esize = 1;			enumber = width;		}		fill_block(fbdev, dst, enumber, height, esize, color);	}	DBGLEAVE(2);	return;}/* Setup a gfx DMA transfer to a rectangular area. * A color parameter can be specified for transparent copy. * Transfer direction can be setup to use either incremental or decremental * addresses. * Source and destination must be elem size aligned. */static inline void transfer_block(struct omapfb_device *fbdev,				  unsigned long src, unsigned long dst,				  unsigned long img_width,				  unsigned long enumber, unsigned long height,				  int esize, u32 bg_color, int flags){	s16	eidx;	s16	s_fidx, d_fidx;	int	lch;	eidx = 1;	s_fidx = img_width - enumber * esize + 1;	d_fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1;	if (flags & COPY_MODE_REV_DIR) {		eidx = -2 * esize + 1;		s_fidx = -s_fidx + eidx + 1;		d_fidx = -d_fidx + eidx + 1;	}	DBGPRINT(2, "src:%#010x dst:%#010x enumber:%d height:%d "		 "esize:%d eidx:%d s_fidx:%d d_fidx bg_color:%#010x flags:%d\n",		 src, dst, enumber, height, esize, eidx, s_fidx, d_fidx,		 bg_color, flags);	if (gfxdma_get_lch(&fbdev->gfx, &lch)) {		PRNERR("ioctl interrupted\n");		return;	}	gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height,			      src, OMAP_DMA_AMODE_DOUBLE_IDX,			      dst, OMAP_DMA_AMODE_DOUBLE_IDX);	gfxdma_set_lch_index(lch, eidx, s_fidx, eidx, d_fidx);	if (flags & COPY_MODE_TRANSPARENT)		gfxdma_set_lch_color(lch, bg_color, OMAP_DMA_TRANSPARENT_COPY);	else		gfxdma_set_lch_color(lch, 0, OMAP_DMA_COLOR_DIS);	gfxdma_enqueue(&fbdev->gfx, lch);	DUMP_DMA_REGS(lch);}/* Copy a rectangular area or an image to another rectangular area. * A color parameter can be specified for transparent copy. * Transfer direction can be setup to use either incremental or decremental * addresses. * Currently both source and destination area must be entirely contained in * frame buffer memory. * The largest possible transfer elem size will be determined according to * source and destination address alignment, dividing the transfer into more * parts if necessary. */static inline void copy_data(struct omapfb_device *fbdev,			     unsigned long src, unsigned long dst,			     unsigned long width, unsigned long height,			     u32 bg_color, int flags){	struct fb_info	 *fbi = fbdev->fb_info;	int		 esize, stripe_esize;	int		 step, rest, enumber;	unsigned long	 img_width;	static const int esize_arr[] = {4, 1, 2, 1};	int		 rev;	/* Check alignment constraints */	esize = esize_arr[(src ^ dst) & 3];	rev = flags & COPY_MODE_REV_DIR;	if (rev) {		rest = src & (esize - 1);		if (rest > width)			rest = width;		src -= rest ? rest : esize;		dst -= rest ? rest : esize;	} else {		rest = esize - (src & (esize - 1));		if (rest > width)			rest = width;	}	if (width < esize)		rest = width;	img_width = flags & COPY_MODE_IMAGE ? width : fbi->fix.line_length;	DBGPRINT(2, "\nrev=%d src=%#010lx dst=%#010lx \n"		 "esize=%d width=%d rest=%d\n",		 rev, src, dst, esize, width, rest);	if (rest) {		/* Transfer this unaligned stripe, so that afterwards		 * we have both src and dst 16bit or 32bit aligned.		 */		if (rest == 2) {			/* Area body is 32bit aligned */			stripe_esize = 2;			enumber = 1;			step = rev ? -esize : 2;			width -= 2;		} else {			stripe_esize = 1;			enumber = rest;			step = rev ? -esize : rest;		}		transfer_block(fbdev, src, dst, img_width, enumber, height,			       stripe_esize, bg_color, flags);		src += step;		dst += step;	}	if (width) {		/* Transfer area body */		enumber = (width & ~(esize - 1)) / esize;		transfer_block(fbdev, src, dst, img_width, enumber, height,			       esize, bg_color, flags);		step = enumber * esize;		width -= step;		if (rev)			step = -step + esize - width;		src += step;		dst += step;	}	if (width) {		/* Transfer the remaining unaligned stripe */		if (width == 2) {			stripe_esize = 2;			enumber = 1;		} else {			stripe_esize = 1;			enumber = width;		}		transfer_block(fbdev, src, dst, img_width, enumber, height,			       stripe_esize, bg_color, flags);	}	DBGLEAVE(2);}/* Copy a rectangular area in the frame buffer to another rectangular area. * Calculate the source and destination addresses. * Transfer direction will be determined taking care of possible area * overlapping. * Currently both source and destination area must be entirely contained in * frame buffer memory, in case of frame flipping source and destination frame * respectively. */static void omapfb_copyarea(struct fb_info *fbi,				   const struct fb_copyarea *area){	struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;	int		width = area->width, height = area->height;	int		sx = area->sx, sy = area->sy;	int		dx = area->dx, dy = area->dy;	unsigned long	dst, dst_ofs, src, src_ofs;	unsigned long	end_ofs;	int		bpp = fbi->var.bits_per_pixel;	int		flags;	DBGENTER(2);	if (!width || !height)		goto exit;	/* If IRQs are disabled we can't use DMA */	if (irqs_disabled()) {		cfb_copyarea(fbi, area);		goto exit;	}	src = fbdev->lcddma_handle;	dst = src;	src_ofs = fbdev->src_frame_org + sx * bpp / 8 +		  sy * fbi->fix.line_length;	dst_ofs = fbdev->dst_frame_org + dx * bpp / 8 +		  dy * fbi->fix.line_length;	end_ofs = (height - 1) * fbi->fix.line_length + width * bpp / 8;	src += src_ofs;	dst += dst_ofs;	DBGPRINT(2, "src:%#010lx dst:%#010lx end_ofs:%#010lx\n",		    src, dst, end_ofs);	/* Currently we support only transfers where both source and destination	 * area is contained entirely in fbmem. This is because of DMA memory	 * constraints.	 */	if (src_ofs + end_ofs > fbdev->lcddma_mem_size ||	    dst_ofs + end_ofs > fbdev->lcddma_mem_size)		goto exit;	flags = 0;	if ((dy == sy && dx > sx) || (dy > sy)) {		flags = COPY_MODE_REV_DIR;		src += end_ofs;		dst += end_ofs;	}	width = width * bpp / 8;	copy_data(fbdev, src, dst, width, height, 0, flags);exit:	DBGLEAVE(2);}/* Copy an image to a rectangular area in the frame buffer. * A color parameter can be specified for transparent copy. * Calculate the source and destination addresses. * Transfer direction will be determined taking care of possible area * overlapping. * Currently both source and destination area must be entirely contained in * frame buffer memory, in case of frame flipping source and destination frame * respectively. */static void do_imageblit(struct fb_info *fbi, const struct fb_image *image,			 int flags){	struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;	int		width = image->width, height = image->height;	int		dx = image->dx, dy = image->dy;	unsigned long	dst, dst_ofs;	unsigned long	dst_end_ofs;	int		bpp = fbi->var.bits_per_pixel;	u32		bg_color;	DBGENTER(2);	if (!width || !height)		goto exit;	/* bpp conversion is not supported, let the default function handle it.	 * Note that image->depth is either 1 for monochrome image, or equals	 * bpp of the current video mode, so we can't rely on it.	 * If IRQs are disabled we can't use DMA.	 */	if (image->depth != bpp || irqs_disabled()) {		if (!(flags & COPY_MODE_TRANSPARENT))			cfb_imageblit(fbi, image);		goto exit;	}	dst = fbdev->lcddma_handle;	dst_ofs = fbdev->dst_frame_org +		  dx * bpp / 8 + dy * fbi->fix.line_length;	dst_end_ofs = (height - 1) * fbi->fix.line_length + width * bpp / 8;	dst += dst_ofs;	DBGPRINT(2, "data:%#010lx dst:%#010lx dst_end_ofs:%#010lx\n",		    image->data, dst, dst_end_ofs);	 /* Check that both source and destination is DMA -able */	if (dst_ofs + dst_end_ofs > fbdev->lcddma_mem_size)		goto exit;	if (((unsigned long)image->data < (unsigned long)fbdev->lcddma_base) ||	    ((unsigned long)image->data + width * bpp / 8 * height >	     (unsigned long)fbdev->lcddma_base + fbdev->lcddma_mem_size)) {		if (!(flags & COPY_MODE_TRANSPARENT))		    	cfb_imageblit(fbi, image);		goto exit;	}	bg_color = image->bg_color;	if (flags & COPY_MODE_TRANSPARENT) {		switch (bpp) {		case 8:			bg_color |= bg_color << 8;			/* Fall through */		case 16:			bg_color |= bg_color << 16;		}	}	width = width * bpp / 8;	flags |= COPY_MODE_IMAGE;	copy_data(fbdev, (unsigned long)image->data, dst, width, height,		  bg_color, flags);exit:	DBGLEAVE(2);

⌨️ 快捷键说明

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