嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第八天-高级驱动framebuffer(物联技术666)

news2024/9/22 11:35:24

链接:https://pan.baidu.com/s/1cd7LOSAvmPgVRPAyuMX7Fg?pwd=1688
提取码:1688

帧缓冲(framebuffer)设备应用于linux显示技术方面。因为linux的显示平台已经全部基于framebuffer,所以目前在linux环境下开发图形化界面、游戏、影视软件等可视化应用时都必须用到帧缓冲技术,而现在随着消费逐渐娱乐化的大趋势,可视化应用已经在产品开发中越来越重要,因此,对于帧缓冲技术的理解和掌握就非常重要了。

1 Frambuffer介绍

  帧缓冲在linux体系中居于上层应用和底层显示设备之间,如下图所示。它的设计意图是对上层应用屏蔽掉低层不同硬件的操作细节:对于不同厂家不同类型的显示硬件,由于各自厂商在技术上扬长避短的需要,所以在具体的细节比如寄存器数量和种类的设计上就会存在相当大的差异,而且对于各个寄存器的初始化的定义和引脚信号的定义也不近相同,这样即便是两种性能相近的产品,例如夏普3.5寸LCD模块与三星的3.5寸模块其操作细节也截然不同。如果让擅长于开发图形界面的开发人员费尽心思去琢磨属于硬件范畴的液晶模块寄存器写入时序问题,无疑是很大的浪费。因此,需要在上层开发和底层设备之间加入一个中间层以节省开发人员的时间和精力。

2 Frambuffer显示原理

  帧缓冲类似一个蓄水池,存放来自用户进程的数据,然后把这些数据再输入显示设备中。对于用户而言,帧缓冲就是内存中的一块区域,可以读、写、映射。只要在初始化阶段把显示设备映射到用户进程空间,可以理解为将屏幕中的每一点和帧缓冲的每一点一一对应起来。这样接下来就可以对这块内存区域填充任何已经定义的像素以及颜色,而屏幕也就可以根据刚才写入的像素及颜色呈现出五彩缤纷的画面。

3 2.6.25内核Frambuffer相关的数据结构

  相关的数据结构从运行环境可以分为用户空间和内核空间两类。在用户空间内使用的数据结构主要有fb_fix_screeninfo和fb_var_screeninfo。在内核空间使用的主要数据结构为fb_info。

  首先介绍fb_fix_screeninfo,该数据结构定义了一些系统运行期间不能改变的信息,例如设备名,屏幕的像素数量,缓冲区的首址和长度等。这类信息一般通过ioctl函数获得。下面列出了fb_fix_screeninfo 的主要内容:

C/C++ code

struct fb_fix_screeninfo {

       char id[16];                   /* 设备名*/

       unsigned long smem_start;     /* frame buffer 缓冲区起始地址(物理地址)*/

                                    

       __u32 smem_len;                  /* 缓冲区长度*/

       __u32 type;                   /* 设备类型,例如TFT或STN*/

       ……

       __u32 visual;                 /* 色彩类型,真彩色、假彩色或单色*/ 

     ……

       __u32 line_length;          /* 屏幕上每行的字节数   */

       unsigned long mmio_start;     /* IO映射区起始地址(物理地址)   */

       __u32 mmio_len;                   /* IO 映射区长度  */

       __u32 accel;                  /* 指出使用的加速卡是哪些特定的芯片 */

       __u16 reserved[3];         /* 系统保留*/

 };

  相对应的,fb_var_screeninfo定义了一些在系统运行期间可以改变的信息。例如像素深度、灰度级、颜色格式、时序,屏幕边缘空白区等。下表中列出了fb_var_screeninfo的主要内容:

C/C++ code

struct fb_var_screeninfo {

       __u32 xres;                   /* visible resolution 可见分辨率 */

       __u32 yres;

       __u32 xres_virtual;         /* virtual resolution 虚拟分辨率 */

       __u32 yres_virtual;

       __u32 xoffset;                /* 从虚拟分辨率到可见分辨率的偏移量*/

       __u32 yoffset;               

       __u32 bits_per_pixel;             /* 像素深度                   */

       __u32 grayscale;            /* 灰度级 */

       struct fb_bitfield red;            

       struct fb_bitfield green;  

       struct fb_bitfield blue;

       struct fb_bitfield transp;  /* 透明度               */   

       __u32 nonstd;                /* 非标准像素格式 */

     ……

       __u32 pixclock;                     /* 像素时钟,单位是皮秒*/

       __u32 left_margin;             /* 左侧边缘区*/

       __u32 right_margin;                  /*右侧边缘区   */

       __u32 upper_margin;            /*顶部边缘区   */

       __u32 lower_margin;

       __u32 hsync_len;           /*水平扫描边缘区   */

       __u32 vsync_len;           /*垂直扫描边缘区   */

       …….

 };

  下图标出了各种边缘区在整个屏幕上的位置。

 

  内核级Fb_info

C/C++ code

struct fb_info {

       int node;                 /* 设备节点 */

       int flags;

       struct fb_var_screeninfo var;  /* 当前可变参数 */

       struct fb_fix_screeninfo fix;     /* 当前固定参数 */

       struct fb_monspecs monspecs;       /* 当前监视器特征 */

       struct work_struct queue;       /* 帧缓冲事件队列 */

       struct fb_pixmap pixmap;       /* 图象硬件映射变量 */

       struct fb_pixmap sprite;      /* 光标硬件映射变量 */

       struct fb_cmap cmap;            /* 当前颜色映射变量 */

       struct list_head modelist;    /* 模式列表*/

       struct fb_videomode *mode;   /* 当前模式*/

     ......

       struct fb_ops *fbops;   /* 该指针指向驱动函数集 */

       ……

       struct device *dev;         /* 代表此帧缓冲设备 */

     ……

       char __iomem *screen_base;  /* IO映射基址(虚地址) */

       unsigned long screen_size;     /* Amount of ioremapped VRAM or 0 */ 

       void *pseudo_palette;            /* 调色板内存地址 */ 

     ……

 };

  fb_info是显示驱动工作的主要载体,它定义了当前显示驱动和控制台有关的全部信息。显示驱动的实现形式就是先初始化fb_info各项,用来设置LCD控制器。以后大部分工作是:应用层通过ioctl系统调用fb_ops中的函数,来获得或修改fix、var变量中值,再写到寄存器中;或修改调色板等操作。如果在应用层中将要显示的两帧图像使用的调色板不同,就由fb_ops中的函数实现,后者获得调色板在内存的地址,修改其中的像素值来实现。

Fb_ops里面的函数指针很多,这些函数指针所指向的一般是各个硬件显卡自带的底层驱动函数,如果读者要自己开发一种专门的显卡,在fb_ops这个结构里必然要用指针把这种显卡专用的那些函数列出来。我们这里只简单介绍其中两个函数指针:

C/C++ code

int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);

  此指针指向的函数是用来检查前面提到的可变显示参数的,例如像素深度、边缘区宽度或深度等。注意这里的不会修改参数。

C/C++ code

int (*fb_set_par)(struct fb_info *info);

  此处所指的函数就可以对显示参数作出实质性的修改了。

4 Frambuffer驱动实现框架

  这里我们不再重复大家已经比较熟悉的驱动程序注册和注销两个过程。我们以fbmem.c中的几个重要函数为对象,解释一下在注册之后到注销之前帧缓冲驱动的大致步骤。之所以选择fbmem.c中的函数,还是因为这个文件中的函数具有一定的代表性,读者在了解它们的大致结构之后,就可以举一反三,来分析和理解其它具体显卡的驱动程序了。

  这几个函数分别是fb_mmap,fb_set_var和 fb_ioctl。

  Fb_mmap顾名思义其任务是完成设备到系统内存(虚拟地址)之间的映射。

C/C++ code

static int

 fb_mmap(struct file *file, struct vm_area_struct * vma)

 {

       int fbidx = iminor(file->f_path.dentry->d_inode);

       struct fb_info *info = registered_fb[fbidx];

       struct fb_ops *fb = info->fbops;

       unsigned long off;

       unsigned long start;

       u32 len;

       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))

              return -EINVAL;

       off = vma->vm_pgoff  < < PAGE_SHIFT;

       if (!fb)

              return -ENODEV;

       if (fb->fb_mmap) { //意思是:如果驱动程序自带了mmap函数,那就用它自己的

              int res;

              lock_kernel(); //上大内核锁

              res = fb->fb_mmap(info, vma); //调用驱动程序自己的mmap函数

              unlock_kernel();

              return res;

       }

       lock_kernel();

       start = info->fix.smem_start;  //注意,这里指向了设备的物理地址

       len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); //调整对齐后长度

       if (off >= len) {

              /* 对应于I/O端口统一编址的情况 */

              off -= len;

              if (info->var.accel_flags) {

                     unlock_kernel();

                     return -EINVAL;

              }

              start = info->fix.mmio_start;//当I/O端口统一编址时就使用端口的物理地址

              len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);

       }

       unlock_kernel();

       start &= PAGE_MASK;

       if ((vma->vm_end - vma->vm_start + off) > len) //判断虚拟内存长度是否超越实际长度

              return -EINVAL;

       off += start;

       vma->vm_pgoff = off >> PAGE_SHIFT;

       /* 本内存页作为IO之用,已经保留 */

       vma->vm_flags |= VM_IO | VM_RESERVED;

       fb_pgprotect(file, vma, off); //对帧缓冲的内存页进行标识,不要挪作它用

       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,

                          vma->vm_end - vma->vm_start, vma->vm_page_prot)) //实际的映射操作

              return -EAGAIN;

       return 0;

 }

  这里的映射行为发生在驱动程序初始化阶段。请注意,这些行为是否被囊括在一个名为mmap的函数中并不是问题的关键,我们在开发中真正应该关心的是映射所需要的前提条件如设备物理地址的提取,映射长度的确认以及实际的映射操作。只要在驱动程序的初始化中完成了上述动作,那就算是成功了。因此,不少显卡的驱动程序里是找不到mmap这个函数的,但它们一样工作得很好,原因就是它们已经完成了实际的映射操作。

  下面我们看看fb_set_var函数。它主要完成了显示模式、可变参数的设置。Fb_set_var这样的函数在不同的显示驱动中的具体名称也不一样,但基本上的功能都是完成对于模式和可变参数的控制。某些系统的驱动里fb_set_var是不含fb_check_var这样的函数的。

C/C++ code

sta

  Fb_ioctl函数汇集了很多的功能,包括从内核读取显示设备参数(可变的和固定的都有),设置参数(就是调用上面提到的fb_set_var函数)。这些功能一般没有什么分类方面的限制,开发人员可以把各种自己实现的功能都一古脑放进fb_ioctl中。而且,开发人员也完全可以抛开系统提供的这个fb_ioctl转而实现自己的fb_ioctl。

C/C++ code

static int

fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,

     unsigned long arg)

{

    int fbidx = iminor(inode);

    struct fb_info *info = registered_fb[fbidx]; //设备

    struct fb_ops *fb = info->fbops;       //设备函数指针

    struct fb_var_screeninfo var;          //可变参数

    struct fb_fix_screeninfo fix;           //固定参数

    struct fb_con2fbmap con2fb;

    struct fb_cmap_user cmap;            //调色板

    struct fb_event event;

    void __user *argp = (void __user *)arg;

    int i;

   

    if (!fb)

        return -ENODEV;

    switch (cmd) {

    case FBIOGET_VSCREENINFO:

        return copy_to_user(argp, &info->var,

                    sizeof(var)) ? -EFAULT : 0;//这里是读取可变参数

    case FBIOPUT_VSCREENINFO:

        if (copy_from_user(&var, argp, sizeof(var)))

            return -EFAULT;                //尝试是否可以设置参数?

        acquire_console_sem();               //控制台上锁

        info->flags |= FBINFO_MISC_USEREVENT;

        i = fb_set_var(info, &var);             //设置可变参数

        info->flags &= ~FBINFO_MISC_USEREVENT;

        release_console_sem();               //解锁

        if (i) return i;

        if (copy_to_user(argp, &var, sizeof(var)))

            return -EFAULT;

        return 0;

    case FBIOGET_FSCREENINFO:

        return copy_to_user(argp, &info->fix,    //读取固定参数

                    sizeof(fix)) ? -EFAULT : 0;

    case FBIOPUTCMAP:                    //设置调色板参数

        if (copy_from_user(&cmap, argp, sizeof(cmap)))

            return -EFAULT;

        return (fb_set_user_cmap(&cmap, info));

   

        ……

    case FBIOBLANK:

        acquire_console_sem();

        info->flags |= FBINFO_MISC_USEREVENT;

        i = fb_blank(info, arg);                  //关闭显示器

        info->flags &= ~FBINFO_MISC_USEREVENT;

        release_console_sem();

        return i;

    default:

        if (fb->fb_ioctl == NULL)  //如果存在自定义的fb_ioctl就使用它

            return -EINVAL;

        return fb->fb_ioctl(info, cmd, arg);

    }

}

  从上面的叙述过程中可以看到,对于帧缓冲驱动程序,尽管不同的显示设备可能有不同的特定功能,但是在向内核注册了驱动程序后运行的共同点都是要先进行物理设备与虚拟内存之间的映射(fb_mmap);在操作设备的过程中,fb_set_var由于可以对于设备的运行参数进行控制因而尤为重要。类似的设备参数读写函数还有fb_check_var等,这些函数一般会被包含在fb_ioctl 函数中并被调用。而上述参数的操作对象就是我们在上一节中已经介绍的 fb_info,fb_fix_screeninfo ,fb_var_screeninfo 等数据结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1464382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑死机卡住怎么办 电脑卡住鼠标也点不动的解决方法

在我们使用电脑的过程中,可能由于电脑硬件或者软件的问题,偶尔会出现电脑卡住的情况,很多电脑小白都不知道电脑卡住了怎么办,鼠标也点不动,键盘也没用,一旦发生了这种情况,大家可以来参考一下小编分享的电脑死机卡住的解决方法。 电脑卡住鼠标也点不动的解决方法 方…

java替换jar中的class文件

1、编译好class文件2、找到需要修改class文件的路径3、解压需要替换的文件4、上传编译后的class文件5、重新压缩 在调整java代码过程中会遇到需要改jar包中的class文件的情况&#xff0c;改了如何替换呢&#xff1f; 1、编译好class文件 将需要修改的class文件代码复制到java编…

亿道丨三防平板丨加固平板丨三防加固平板丨改善资产管理

库存资产管理中最重要的部分之一是准确性&#xff1b;过时的库存管理技术会增加运输过程中人为错误、物品丢失或纸张损坏的风险。如今随着三防平板电脑的广泛使用&#xff0c;库存管理也迎来了好帮手&#xff0c;通过使用三防平板电脑能够确保库存管理、数据存储和记录保存的准…

R语言【base】——abs(),sqrt():杂项数学函数

Package base version 4.2.0 Description abs(x) 计算 x 的绝对值&#xff0c;sqrt(x) 计算 x 的正平方根。 Usage abs(x) sqrt(x) Arguments 参数【x】&#xff1a;一个数值或复数向量或数组。 Details 这些都是内部泛型原语函数:可以为它们单独定义方法&#xff0c;也可以…

Python 光速入门课程

首先说一下&#xff0c;为啥小编在即PHP和Golang之后&#xff0c;为啥又要整Python&#xff0c;那是因为小编最近又拿起了 " 阿里天池 " 的东西&#xff0c;所以小编又不得不捡起来大概五年前学习的Python&#xff0c;本篇文章主要讲的是最基础版本&#xff0c;所以比…

基于springboot+vue的靓车汽车销售网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

荧光淬灭剂Tide Quencher 2酸,Tide Quencher 2 acid ,能够与荧光物质发生反应

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;荧光淬灭剂Tide Quencher 2酸&#xff0c;Tide Quencher 2 acid &#xff0c;TQ2 acid 一、基本信息 产品简介&#xff1a;Tide Quencher 2 acid is highly favored in the field of scientific experiments due to…

大语言模型的开山之作—探秘GPT系列:GPT-1-GPT2-GPT-3的进化之路

模型模型参数创新点评价GPT1预训练微调&#xff0c; 创新点在于Task-specific input transformations。GPT215亿参数预训练PromptPredict&#xff0c; 创新点在于Zero-shotZero-shot新颖度拉满&#xff0c;但模型性能拉胯GPT31750亿参数预训练PromptPredict&#xff0c; 创新点…

2024年1月京东冰箱行业数据分析:TOP10品牌销量及销额排行榜

鲸参谋监测的京东平台1月份冰箱市场销售数据已出炉&#xff01; 根据鲸参谋电商数据分析平台显示&#xff0c;今年1月份&#xff0c;京东平台上冰箱的销量超105万件&#xff0c;环比上个月增长约40%&#xff0c;同比去年下滑18%&#xff1b;销售额约30亿元&#xff0c;环比上个…

linux系统消息中间件rabbitmq普通集群的部署

rabbitmq普通集群的部署 普通集群准备环境查询版本对应安装rabbitmq软件启动创建登录用户开启用户远程登录查看端口 部署集群创建数据存放目录和日志存放目录:拷⻉erlang.cookie将其他两台服务器作为节点加⼊节点集群中查看集群状态创建新的队列 普通集群准备环境 配置hosts⽂件…

2.22驱动作业

1.使用GPIO子系统编写LED灯驱动&#xff0c;应用程序测试 2.注册三个按键的中断&#xff0c;只需要写内核代码 1.代码 应用程序&#xff1a; #include<stdlib.h> #include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fc…

Maven depoly:Skipping artifact deployment

问题描述&#xff1a; 使用IDEA执行mvn depoly将本地开发的模块发布到Maven私服时&#xff0c;一直提示&#xff1a;Skipping artifact deployment&#xff0c;自动跳过了depoly部署阶段。 问题分析 Maven构建生命周期中的每一个阶段都是由对应的maven插件执行具体工作的。既然…

Spring AOP 实现原理详解之 CGLIB 动态代理

目录 一. 前言 1.1. Spring AOP 和 CGLIB 是什么关系&#xff1f; 二. CGLIB 代理示例 2.1. pom 包依赖 2.2. 定义实体 2.3. 被代理的类 2.4. CGLIB 代理 2.5. 使用代理 三. CGLIB 代理的流程 四. Spring AOP 中 CGLIB 代理的实现 一. 前言 CGLIB 是一个强大的高性能…

Portraiture有哪些版本?2024最新版本如何下载

Portraiture有多个版本&#xff0c;其中常用的版本包括Portraiture 3和Portraiture 4。 Portraiture 3&#xff1a;该版本支持Adobe Photoshop CC 2019以上版本和Lightroom CC 2015以上版本&#xff0c;适用于Windows 11/10和macOS 11 Big Sur、12 Monterey、13 Ventura等操作…

Java字符集【ASCII,GBK,Unicode】

1.常见字符集 1.标准ASCII字符集 美国信息交换标准代码&#xff0c;包括了英文、符号等。 标准ASCII使用1个字节存储一个字符&#xff0c;首位是0&#xff0c;总共可表示128个字符&#xff0c;对美国人来说完全够用。 2.GBK&#xff08;汉字内码扩展规范&#xff0c;国标&#…

时域相位分析技术 和空域相位分析技术

l) 时域相位分析技术 在光 学测量 的许 多情况 下 &#xff0c; 时变图像信 号 的背景光 强 与调制 度可 以看作是 常 数 &#xff0c;并且 其光 强 随时 间 的变化也满足 正 弦条件 。 那 么针 对某 一 空 间采样 点 (x &#xff0c;y) &#xff0c; 某时刻 采 集到 的光 强 可…

PYTHON-使用正则表达式进行模式匹配

目录 Python 正则表达式Finding Patterns of Text Without Regular ExpressionsFinding Patterns of Text with Regular ExpressionsCreating Regex ObjectsMatching Regex ObjectsReview of Regular Expression MatchingMore Pattern Matching with Regular ExpressionsGroupi…

基于springboot+vue的酒店客房管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【数据结构初阶 6】二叉树:堆的基本操作 + 堆排序的实现

文章目录 &#x1f308; Ⅰ 二叉树的顺序结构&#x1f308; Ⅱ 堆的概念与性质&#x1f308; Ⅲ 堆的基本操作01. 堆的定义02. 初始化堆03. 堆的销毁04. 堆的插入05. 向上调整堆06. 堆的创建07. 获取堆顶数据08. 堆的删除09. 向下调整堆10. 判断堆空 &#x1f308; Ⅳ 堆的基本…

【Git企业实战开发】Git常用开发流操作总结

【Git企业实战开发】Git常用开发流操作总结 大家好 我是寸铁&#x1f44a; 总结了一篇Git常用开发流操作总结的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 现在刚做项目的伙伴&#xff0c;可能你之前学过git&#xff0c;但是一实战发现不熟悉 没关系&#xff0c;看寸铁这篇…