第18章LCD设备驱动之Linux 帧缓冲设备驱动的fb_ops成员函数

18.7 Linux 帧缓冲设备驱动的fb_ops成员函数

    fb_info 中的 fp_ops 是使得帧缓冲设备工作所需函数的集合,它们最终与 LCD 控制器硬件打交道。

    fb_check_var()用于调整可变参数,并修正为硬件所支持的值;fb_set_par()根据屏幕参数设置具体读写 LCD 控制器的寄存器以使得 LCD 控制器进入相应的工作状态。对于 fb_ops 中的 fb_fillrect()、fb_copyarea()和 fb_imageblit()成员函数,通常直接使用对应的通 用 的 cfb_fillrect() 、 cfb_copyarea() 和 cfb_imageblit() 函 数 即 可 。

     cfb_fillrect() 函 数 定 义 在drivers/video/fbdev/core/cfbfillrect.c文件中

void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
{
        unsigned long pat, pat2, fg;
        unsigned long width = rect->width, height = rect->height;
        int bits = BITS_PER_LONG, bytes = bits >> 3;
        u32 bpp = p->var.bits_per_pixel;
        unsigned long __iomem *dst;
        int dst_idx, left;

        if (p->state != FBINFO_STATE_RUNNING)
                return;

        if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
            p->fix.visual == FB_VISUAL_DIRECTCOLOR )
                fg = ((u32 *) (p->pseudo_palette))[rect->color];
        else
                fg = rect->color;

        pat = pixel_to_pat(bpp, fg);

        dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
        dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
        dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
        /* FIXME For now we support 1-32 bpp only */
        left = bits % bpp;
        if (p->fbops->fb_sync)
                p->fbops->fb_sync(p);
        if (!left) {
                u32 bswapmask = fb_compute_bswapmask(p);
                void (*fill_op32)(struct fb_info *p,
                                  unsigned long __iomem *dst, int dst_idx,
                                  unsigned long pat, unsigned n, int bits,
                                  u32 bswapmask) = NULL;

                switch (rect->rop) {
                case ROP_XOR:
                        fill_op32 = bitfill_aligned_rev;
                        break;
                case ROP_COPY:
                        fill_op32 = bitfill_aligned;
                        break;
                default:
                        printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
                        fill_op32 = bitfill_aligned;
                        break;
                }
                while (height--) {
                        dst += dst_idx >> (ffs(bits) - 1);
                        dst_idx &= (bits - 1);
                        fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
                                  bswapmask);
                        dst_idx += p->fix.line_length*8;
                }
        } else {
                int right, r;
                void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
                                int dst_idx, unsigned long pat, int left,
                                int right, unsigned n, int bits) = NULL;
#ifdef __LITTLE_ENDIAN
                right = left;
                left = bpp - right;
#else
                right = bpp - left;
#endif
                switch (rect->rop) {
                case ROP_XOR:
                        fill_op = bitfill_unaligned_rev;
                        break;
                case ROP_COPY:
                        fill_op = bitfill_unaligned;
                        break;
                default:
                        printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
                        fill_op = bitfill_unaligned;
                        break;
                }
                while (height--) {
                        dst += dst_idx / bits;
                        dst_idx &= (bits - 1);
                        r = dst_idx % bpp;
                        /* rotate pattern to the correct start position */
                        pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
                        fill_op(p, dst, dst_idx, pat2, left, right,
                                width*bpp, bits);
                        dst_idx += p->fix.line_length*8;
                }
        }
}

EXPORT_SYMBOL(cfb_fillrect);

cfb_copyarea()定义在drivers/video/fbdev/core/cfbcopyarea.c文件中

void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
        u32 height = area->height, width = area->width;
        unsigned long const bits_per_line = p->fix.line_length*8u;
        unsigned long __iomem *base = NULL;
        int bits = BITS_PER_LONG, bytes = bits >> 3;
        unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
        u32 bswapmask = fb_compute_bswapmask(p);

        if (p->state != FBINFO_STATE_RUNNING)
                return;

        /* if the beginning of the target area might overlap with the end of
        the source area, be have to copy the area reverse. */
        if ((dy == sy && dx > sx) || (dy > sy)) {
                dy += height;
                sy += height;
                rev_copy = 1;
        }

        // split the base of the framebuffer into a long-aligned address and the
        // index of the first bit
        base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
        dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
        // add offset of source and target area
        dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
        src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;

        if (p->fbops->fb_sync)
                p->fbops->fb_sync(p);

        if (rev_copy) {
                while (height--) {
                        dst_idx -= bits_per_line;
                        src_idx -= bits_per_line;
                        bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
                                base + (src_idx / bits), src_idx % bits, bits,
                                width*p->var.bits_per_pixel, bswapmask);
                }
        } else {
                while (height--) {
                        bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
                                base + (src_idx / bits), src_idx % bits, bits,
                                width*p->var.bits_per_pixel, bswapmask);
                        dst_idx += bits_per_line;
                        src_idx += bits_per_line;
                }
        }
}

EXPORT_SYMBOL(cfb_copyarea);

cfb_imageblit()定义在drivers/video/fbdev/core/cfbimgblt.c 文件中

void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
{
        u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
        u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
        u32 width = image->width;
        u32 dx = image->dx, dy = image->dy;
        u8 __iomem *dst1;

        if (p->state != FBINFO_STATE_RUNNING)
                return;

        bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
        start_index = bitstart & (32 - 1);
        pitch_index = (p->fix.line_length & (bpl - 1)) * 8;

        bitstart /= 8;
        bitstart &= ~(bpl - 1);
        dst1 = p->screen_base + bitstart;

        if (p->fbops->fb_sync)
                p->fbops->fb_sync(p);

        if (image->depth == 1) {
                if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
                    p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
                        fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
                        bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
                } else {
                        fgcolor = image->fg_color;
                        bgcolor = image->bg_color;
                }

                if (32 % bpp == 0 && !start_index && !pitch_index &&
                    ((width & (32/bpp-1)) == 0) &&
                    bpp >= 8 && bpp <= 32)
                        fast_imageblit(image, p, dst1, fgcolor, bgcolor);
                else
                        slow_imageblit(image, p, dst1, fgcolor, bgcolor,
                                        start_index, pitch_index);
        } else
                color_imageblit(image, p, dst1, start_index, pitch_index);
}

EXPORT_SYMBOL(cfb_imageblit);

    fb_ops 中的 fb_setcolreg()成员函数实现伪颜色表(针对 FB_VISUAL_TRUECOLORFB_VISUAL_DIRECTCOLOR 模式)和颜色表的填充,其模板如代码清单 18.11 所示。

代码清单 18.11 fb_setcolreg()函数模板

static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 unsigned blue, unsigned transp, struct fb_info *info)
 {
         struct xxxfb_info *fbi = info->par;
         unsigned int val;

         switch (fbi->fb->fix.visual) {
         case FB_VISUAL_TRUECOLOR:
                 /* 真彩色,设置伪颜色表 */
                 if (regno < 16) {
                        u32 *pal = fbi->fb->pseudo_palette;
                         val = chan_to_field(red, &fbi->fb->var.red);
                         val |= chan_to_field(green, &fbi->fb->var.green);
                         val |= chan_to_field(blue, &fbi->fb->var.blue);
                         pal[regno] = val;
                 }
                 break;

         case FB_VISUAL_PSEUDOCOLOR:
                 if (regno < 256) {
                         /* RGB565 模式 */
                         val = ((red >> 0) &0xf800);

                         val |= ((green >> 5) &0x07e0);
                         val |= ((blue >> 11) &0x001f);

                         writel(val, XXX_TFTPAL(regno));
                         schedule_palette_update(fbi, regno, val);
                 }
         break;
         ...
         }

        return 0;
 }

分析:

        对 regno < 16 的判断意味着伪颜色表只有 16 个成员,实际上,它们对应 16种控制台颜色,logo 显示也会使用伪颜色表。


猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/80756125
今日推荐