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

链接: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.mzph.cn/news/694625.shtml

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

相关文章

python opencv图像模糊

目录 一:均值滤波 二:高斯滤波 三:中值滤波 四:双边滤波 在OpenCV中,模糊图片或进行图像平滑处理时常用的方法包括以下几种: 均值滤波 (Blurring): 均值滤波是一种简单的平滑方法,它通过对图像中每个像素的邻域内像素值进行平均来计算新的像素值。在OpenC

ABC341 题解

ABC341 题解 A Description 给定一个数 N N N&#xff0c;求长度 2 N 1 2N1 2N1 的 01 交替的字符串&#xff08;0 开始&#xff09;。 Solution 直接模拟&#xff0c;注意 0-index 是 i m o d 2 i\bmod 2 imod2&#xff0c;1-index 是 ( i 1 ) m o d 2 (i1) \bmod …

js-Vue Router 中的方法,父A-子B-子C依次返回,无法返回到A,BC中形成循环跳转解决

1.常用的方法 在 Vue Router 中&#xff0c;有一些常用的方法用于实现路由导航和管理。以下是一些常见的 Vue Router 方法及其作用&#xff1a; push: router.push(location, onComplete, onAbort) 作用&#xff1a;向路由历史记录中添加一个新条目&#xff0c;并导航到指定的路…

算法-位运算

题目&#xff1a;题目5 一个数组中有一种数出现K次&#xff0c;其他数都出现了M次&#xff0c; M > 1, K < M 找到&#xff0c;出现了K次的数&#xff0c; 要求&#xff0c;额外空间复杂度O(1)&#xff0c;时间复杂度O(N) 思路&#xff1a;遍历数组按位计数&#xff0c;不…

SRS关闭无人观看的流

这里需要使用到SRS自身自带的钩子回调功能&#xff0c;配置文件中有标注&#xff1a; Hook函数&#xff1a; 分为on_publish、on_play、on_stop、on_unpublish、on_dvr等类别&#xff1b; 其中主要介绍on_play、on_stop on_play&#xff1a; 主要用于用户在对srs拉流进行播…

十六进制数

1.做一个收电费程序&#xff0c;要求输入使用的电的度数&#xff08;整数&#xff09;以及电费单价&#xff08;实数&#xff09;&#xff0c;输出总的用电费用。 2.提示并输入一个小写字母数据&#xff0c;输出其对应的ASCII值&#xff0c;以及该小写字母对应的大写字母。 3.提…

Spring设计模式之工厂模式创建Bean对象

BeanFactory和Application是Spring容器中创建和管理Bean对象的接口&#xff0c;但是它们的实现方式不同。 BeanFactory&#xff1a; BeanFactory采用延迟初始化策略&#xff0c;只有应用程序向容器请求特定的Bean时才创建该Bean对象。它的启动速度很快&#xff0c;但在程序运…

MySQL、Redis、Nginx配置优化

文章目录 一、MySQL二、Redis三、Nginx 一、MySQL mysql.cnf [mysqld] binlog_cache_size 128K thread_stack 256K join_buffer_size 2048K max_heap_table_size 512Mdefault_storage_engine InnoDB performance_schema_max_table_instances 400 table_definition_cach…

leetcode hot100组合综合四

本题中&#xff0c;是要求nums中求的总和为target的排列数&#xff0c;因为题中说了&#xff0c;元素顺序不同&#xff0c;则可以视为不同的结果之一。 所以&#xff0c;根据对背包问题的总结&#xff0c;本题中元素可以重复使用&#xff0c;是完全背包并且需要求排列数&#…

.net 微服务 服务保护 自动重试 Polly

1. 概要 实验服务保护&#xff0c;自动重新连接功能。 2.代码 2.1 重复工具 using Polly; using Polly.Retry; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks;namespace WebApplication2 {pu…

c# DotNetty

对于 .NET 开发者来说&#xff0c;DotNetty 是一个开源、高性能的网络库&#xff0c;它是对 Java 平台上流行的 Netty 异步事件驱动网络应用程序框架的一个端口。DotNetty 适用于创建各种网络应用程序&#xff0c;如 IoT (物联网)、游戏服务器以及消息传递系统等。 以下是对 Do…

Redis之缓存击穿问题解决方案

文章目录 一、书接上文二、介绍三、解决方案1. 单例双检锁2. 缓存预热和定时任务 一、书接上文 Redis之缓存雪崩问题解决方案 二、介绍 缓存击穿就是大量并发访问同一个热点数据&#xff0c;一旦这个热点数据缓存失效&#xff0c;则请求压力都来到数据库。 三、解决方案 1…

Redis命令和Redisson对象匹配列表

大家好&#xff0c;Redisson系列再发一文。 多克创新国庆福利继续发&#xff0c;有需要的可以前往官网了解详情&#xff01;&#xff01;&#xff01; Redis命令Redisson对象方法AUTHConfig.setPassword();APPENDRBinaryStream.getOutputStream().write()BITCOUNTRBitSet.ca…

嵌入式Qt 计算器核心算法_1

一.表达式分离算法分析 二.分离算法实现 QCalculatorDec.cpp #include "QCalculatorDec.h"#include <QDebug>QCalculatorDec::QCalculatorDec() {m_exp "";m_result "";QQueue<QString> r split("9.11 ( -3 - 1 ) * -5 &…

C#,整数转为短字符串(Short string)的加解密算法与源代码

1 整数转为短字符串的应用 网站生成的动态 URL 往往以内容序列号id为标识与参数&#xff0c;比如&#xff1a; http://www.jerry.com/tom.aspx?id1 使用 Web Rewrite&#xff0c;可以实现网页静态化&#xff0c;称为&#xff1a; http://www.jerry.com/content/1.html 对…

数学家的趣闻轶事15则

目录 前言趣闻轶事15则参考文献 前言 有人的地方就有江湖&#xff0c;有江湖的地方就有故事。数学本身就是一个江湖&#xff0c;这个江湖也充满着血雨腥风和侠骨柔情&#xff0c;至今流传着各种各样的传说&#xff0c;其中不乏”马踏江湖潇潇事“&#xff0c;也有"何当共…

Centos安装图形化桌面环境

1.使用root远程登录最小化安装的虚拟机 2.执行命令yum groupinstall "X Window System" 这是安装窗口系统 3.执行命令yum grouplist" 检查安装的软件可可以安装的软件 4.执行命令yum groupinstall "Server with GUI" 这是安装图形化界面 5.执行命令sy…

抛弃chatgpt,使用微软的Cursor提升coding效率

Whats Cursor? Cursor编辑器是一个基于GPT-4的代码编辑器&#xff0c;它可以根据用户的自然语言指令或者正在编辑的代码上下文为用户提供代码建议&#xff0c;支持多种编程语言&#xff0c;如Python、Java、C/C#、go等。Cursor编辑器还可以帮助用户重构、理解和优化代码&…

Mybatisplus 传参参数为自定义sql, 使用条件构造器作为参数

1 pom依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version> </dependency> 2 mapper 接口文件 List<TBookOrder> searchDiy(Param(Const…

centos docker jenkins 日志

在 CentOS 系统上运行 Docker 容器中的 Jenkins&#xff0c;查看日志的方法如下&#xff1a; 实时查看 Jenkins 容器的日志&#xff1a; 可以使用 docker logs 命令实时查看 Jenkins 容器的输出日志。 docker logs -f <jenkins_container_name_or_id>-f 参数表示跟随&…