Framebuffer截图_framebuffer_Framebuffer画布

前言

前面我们了解了LCD的基本架构《》,接下来我们拿个具体的实例来分析分析。这样可以了解其大概是如何使用和工作的。

FrameBuffer驱动分析

内核版本:4.20

芯片平台:s3c2410

依然是使用之前的方式进行分析,大部分内容在注释。

(1)装载和卸载函数

static struct platform_driver s3c2410fb_driver = {  .probe    = s3c2410fb_probe,  .remove    = s3c2410fb_remove,  .suspend  = s3c2410fb_suspend,  .resume    = s3c2410fb_resume,  .driver    = {    .name  = "s3c2410-lcd",  },};
int __init s3c2410fb_init(void){ int ret = platform_driver_register(&s3c2410fb_driver); return ret;}
static void __exit s3c2410fb_cleanup(void){ platform_driver_unregister(&s3c2410fb_driver);}
module_init(s3c2410fb_init);module_exit(s3c2410fb_cleanup);

上面比较简单,就是注册一个platform_driver, 控制器一般都是使用platform总线。

(2)probe()

static int s3c2410fb_probe(struct platform_device *pdev){  return s3c24xxfb_probe(pdev, DRV_S3C2410);}
static int s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type){ struct s3c2410fb_info *info; struct s3c2410fb_display *display; struct fb_info *fbinfo; struct s3c2410fb_mach_info *mach_info; struct resource *res; int ret; int irq; int i; int size; u32 lcdcon1; //获取板子配置信息 mach_info = dev_get_platdata(&pdev->dev); //省略...... //display包含了屏幕的分辨率信息等 display = mach_info->displays + mach_info->default_display; //获取中断号 irq = platform_get_irq(pdev, 0);
//分配一个fb_info fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); //保存fbinfo到driver data platform_set_drvdata(pdev, fbinfo);
info = fbinfo->par; info->dev = &pdev->dev; info->drv_type = drv_type; //获取IO资源并申请 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); size = resource_size(res); info->mem = request_mem_region(res->start, size, pdev->name);
//映射为虚拟地址 info->io = ioremap(res->start, size); //获取中断基地址 info->irq_base = info->io + S3C2410_LCDINTBASE;
strcpy(fbinfo->fix.id, driver_name);
//操作寄存器,停止LCDC输出 lcdcon1 = readl(info->io + S3C2410_LCDCON1); writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); //初始化固定参数 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; fbinfo->fix.type_aux = 0; fbinfo->fix.xpanstep = 0; fbinfo->fix.ypanstep = 0; fbinfo->fix.ywrapstep = 0; fbinfo->fix.accel = FB_ACCEL_NONE; //初始化可变参数 fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; //设置操作函数 fbinfo->fbops = &s3c2410fb_ops; fbinfo->flags = FBINFO_FLAG_DEFAULT; fbinfo->pseudo_palette = &info->pseudo_pal; //清除画板 for (i = 0; i < 256; i++) info->palette_buffer[i] = PALETTE_BUFF_CLEAR; //申请中断 ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info); //获取时钟并使能 info->clk = clk_get(NULL, "lcd"); clk_prepare_enable(info->clk);
usleep_range(1000, 1100);
info->clk_rate = clk_get_rate(info->clk);
/* 计算显示所需分配的内存大小 */ for (i = 0; i num_displays; i++) { unsigned long smem_len = mach_info->displays[i].xres;
smem_len *= mach_info->displays[i].yres; smem_len *= mach_info->displays[i].bpp; smem_len >>= 3; if (fbinfo->fix.smem_len < smem_len) fbinfo->fix.smem_len = smem_len; }
  /* 初始化显存,这里面设置了DMA */ ret = s3c2410fb_map_video_memory(fbinfo);   //根据屏幕信息初始化fbinfo中的可变参数 fbinfo->var.xres = display->xres; fbinfo->var.yres = display->yres; fbinfo->var.bits_per_pixel = display->bpp;  //初始化LCDC相关寄存器 s3c2410fb_init_registers(fbinfo);
   //注册framebuffer ret = register_framebuffer(fbinfo);
return 0;
}

上面省略了一些错误判断。

上面总结下来就两个部分:

1. 根据屏幕信息填充fb_info, 然后调用register_framebuffer进行注册

2. LCDC相对应的寄存器的配置(硬件平台相关的)

(3)各种操作屏幕的函数

static struct fb_ops s3c2410fb_ops = {  .owner    = THIS_MODULE,  .fb_check_var  = s3c2410fb_check_var, //检查可变参数合法性  .fb_set_par  = s3c2410fb_set_par, //设置可变参数  .fb_blank  = s3c2410fb_blank, //设置开关屏  .fb_setcolreg  = s3c2410fb_setcolreg, //设置颜色寄存器     //下面三个都是使用内核自带的函数  .fb_fillrect  = cfb_fillrect, //绘制矩形  .fb_copyarea  = cfb_copyarea, //区域拷贝  .fb_imageblit  = cfb_imageblit,//绘制位图};

简单看几个函数,其实就是对寄存器的操作。

static int s3c2410fb_set_par(struct fb_info *info){    //设置参数信息  struct fb_var_screeninfo *var = &info->var;      switch (var->bits_per_pixel) {  case 32:  case 16:  case 12:    info->fix.visual = FB_VISUAL_TRUECOLOR;    break;  case 1:    info->fix.visual = FB_VISUAL_MONO01;    break;  default:    info->fix.visual = FB_VISUAL_PSEUDOCOLOR;    break;  }
info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; //设置寄存器,该函数中都是寄存器的操作 s3c2410fb_activate_var(info); return 0;}

static int s3c2410fb_blank(int blank_mode, struct fb_info *info){  struct s3c2410fb_info *fbi = info->par;  void __iomem *tpal_reg = fbi->io;
dprintk("blank(mode=%d, info=%p)n", blank_mode, info); tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; //根据开关设置寄存器 if (blank_mode == FB_BLANK_POWERDOWN) s3c2410fb_lcd_enable(fbi, 0); else s3c2410fb_lcd_enable(fbi, 1);
if (blank_mode == FB_BLANK_UNBLANK) writel(0x0, tpal_reg); else { dprintk("setting TPAL to output 0x000000n"); writel(S3C2410_TPAL_EN, tpal_reg); }
return 0;}

这些操作函数和裸机程序基本差不多,就是一些对寄存器的操作。

总结

上面其实没有多少内容,我们并不需要过多关注细节。比如寄存器配置的含义之类的,因为每个平台都不一样,即使你把这款芯片的所有细节理解了,换个平台,依然要重新来。所以我们应该理解的是框架。

随着技术的发展,特别是GPU的出现,单纯使用Framebuffer来显示越来越少,它已经渐渐成为DRM的一部分了。特别是现在的Android设备, 对显示要求越来越高。后期会带来一些DRM相关的文章!

end

往期推荐

限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注