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 + -
显示快捷键?