Linux驱动分析之Framebuffer驱动

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

 前言

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


FrameBuffer驱动分析

内核版本:4.20

芯片平台:s3c2410

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

(1)装载和卸载函数

staticstructplatform_drivers3c2410fb_driver= {
  .probe=s3c2410fb_probe,
  .remove=s3c2410fb_remove,
  .suspend=s3c2410fb_suspend,
  .resume=s3c2410fb_resume,
  .driver= {
    .name="s3c2410-lcd",
  },
};
int__inits3c2410fb_init(void)
{
intret=platform_driver_register(&s3c2410fb_driver);
returnret;
}
staticvoid__exits3c2410fb_cleanup(void)
{
platform_driver_unregister(&s3c2410fb_driver);
}
module_init(s3c2410fb_init);
module_exit(s3c2410fb_cleanup);

image.gif

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

(2)probe()

staticints3c2410fb_probe(structplatform_device*pdev)
{
returns3c24xxfb_probe(pdev, DRV_S3C2410);
}
staticints3c24xxfb_probe(structplatform_device*pdev,
enums3c_drv_typedrv_type)
{
structs3c2410fb_info*info;
structs3c2410fb_display*display;
structfb_info*fbinfo;
structs3c2410fb_mach_info*mach_info;
structresource*res;
intret;
intirq;
inti;
intsize;
u32lcdcon1;
//获取板子配置信息mach_info=dev_get_platdata(&pdev->dev);
//省略......//display包含了屏幕的分辨率信息等display=mach_info->displays+mach_info->default_display;
//获取中断号irq=platform_get_irq(pdev, 0);
//分配一个fb_infofbinfo=framebuffer_alloc(sizeof(structs3c2410fb_info), &pdev->dev);
//保存fbinfo到driver dataplatform_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<mach_info->num_displays; i++) {
unsignedlongsmem_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);
//注册framebufferret=register_framebuffer(fbinfo);
return0;
}

image.gif

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

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

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

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

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

staticstructfb_opss3c2410fb_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,//绘制位图};

image.gif

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

    • s3c2410fb_set_par
    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;
    }

    image.gif

      • s3c2410fb_blank
      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 0x000000\n");
          writel(S3C2410_TPAL_EN, tpal_reg);
        }
        return 0;
      }

      image.gif

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


      总结

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

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

      相关文章
      |
      2天前
      |
      算法 Linux 编译器
      技术笔记:LINUX2.6.32下的进程分析
      技术笔记:LINUX2.6.32下的进程分析
      |
      2天前
      |
      监控 Linux 应用服务中间件
      探索Linux中的`ps`命令:进程监控与分析的利器
      探索Linux中的`ps`命令:进程监控与分析的利器
      |
      3天前
      |
      运维 监控 网络协议
      Linux 下的性能监控与分析技巧
      在Linux环境中,命令行工具助力服务器管理和故障排查。通过示例展示如何监控网络、TCP连接、CPU及内存使用。例如,用`netstat`结合`awk`查TOP 20高频率IP访问80端口,识别DDoS迹象;`netstat -nat`统计TCP状态;`ps -aux`排序列出CPU和内存消耗大的进程;`find`加`tar`查找并压缩`.conf`文件。掌握这些命令提升运维效率。
      10 1
      |
      6天前
      |
      Linux 数据处理 开发者
      深入解析Linux中的paste命令:数据处理与分析的得力助手
      `paste`命令在Linux中是数据处理的利器,它按列拼接多个文件内容,支持自定义分隔符和从标准输入读取。例如,合并`file1.txt`和`file2.txt`,使用`paste file1.txt file2.txt`,默认以制表符分隔;若要使用逗号分隔,可运行`paste -d &#39;,&#39; file1.txt file2.txt`。当文件行数不同时,较短文件后会填充空白行。结合管道符与其他命令使用,如`cat file1.txt | paste -s`,可按行合并内容。注意文件大小可能影响性能。
      |
      6天前
      |
      Linux 编译器 测试技术
      探索Linux中的objcopy命令:数据处理与分析的得力助手
      `objcopy`是GNU工具集中的实用程序,用于复制和转换二进制目标文件,如ELF到S-record。它支持格式转换、内容提取和修改,如移除调试信息。命令参数包括指定输入/输出格式和复制特定段。示例用途有:`objcopy -O binary input.elf output.bin`(ELF转二进制)和`objcopy -j .text input.elf output.o`(复制.text段)。使用时注意文件格式、备份原始文件并查阅文档。对于处理和分析二进制数据,`objcopy`是不可或缺的工具。
      |
      6天前
      |
      移动开发 数据挖掘 Linux
      探索Linux命令之nl:数据处理与分析的得力助手
      `nl`命令是Linux下用于为文本文件添加行号的工具,支持自定义格式和空行处理。它可以显示行首或行尾的行号,并能处理逻辑页。常用参数包括`-b`(控制空行行号)、`-n`(设定行号位置和是否补零)、`-w`(设定行号宽度)。示例用法如`nl -b a -n rz -w 3 filename.txt`。在处理大文件时需谨慎,并注意备份原始文件。nl是数据分析时的实用工具。
      |
      10天前
      |
      数据挖掘 Linux 数据处理
      探索Linux下的Lua命令:轻量级脚本语言在数据处理和分析中的应用
      **探索Linux上的Lua:轻量级脚本语言用于数据处理。Lua通过命令行解释器执行,适用于游戏开发、数据分析及自动化。特点包括小巧、高效、可扩展和动态类型。使用`lua`或`luajit`,配合-e、-l、-i参数执行脚本或互动模式。示例:执行`hello.lua`脚本打印&quot;Hello, Lua!&quot;。最佳实践涉及版本兼容、性能优化、使用C API、测试和文档编写。**
      |
      10天前
      |
      JSON 运维 安全
      深入探索Linux的lsns命令:处理与分析Linux命名空间
      `lsns`命令是Linux中用于查看命名空间信息的工具,帮助管理和隔离系统资源。它显示命名空间的状态、类型、进程和挂载点,适用于性能优化、故障排查。命令特点包括丰富的参数选项(如 `-t`、`-p`、`-n`),清晰的表格输出和JSON格式支持。示例:列出所有命名空间用`lsns`,列出网络命名空间用`lsns -t net`。使用时注意权限,结合其他工具,并考虑版本兼容性。
      |
      13天前
      |
      Linux
      【GEC6818开发板】Linux驱动中printk无法在终端输出显示
      【GEC6818开发板】Linux驱动中printk无法在终端输出显示
      |
      13天前
      |
      Linux 程序员 芯片
      【Linux驱动】普通字符设备驱动程序框架
      【Linux驱动】普通字符设备驱动程序框架