当前位置: 首页 > 编程日记 > 正文

15.linux-LCD层次分析(详解)

如果我们的系统要用GUI(图形界面接口),这时LCD设备驱动程序就应该编写成frambuffer接口,而不是像之前那样只编写操作底层的LCD控制器接口。

什么是frambuffer设备?

   frambuffer设备层是对图像设备的一种抽象,它代表了视频硬件的帧缓存,使得应用程序通过定义好的接口就可以访问硬件。所以应用程序不需要考虑底层的(寄存器级)的操作。应用程序对设备文件的访问一般在/dev目录,如 /dev/fb*。


内核中的frambuffer在drivers/video/fbmem.c(fb: frame buffer)

1.我们进入fbmem.c找到它的入口函数:

static  int __init  fbmem_init(void)
{create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);if (register_chrdev(FB_MAJOR,"fb",&fb_fops))           //(1)创建字符设备printk("unable to get major %d for fb devs\n", FB_MAJOR);fb_class = class_create(THIS_MODULE, "graphics");       //创建类if (IS_ERR(fb_class)) {printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));fb_class = NULL;}return 0;
}

(1)创建字符设备"fb", FB_MAJOR=29,主设备号为29,我们cat /proc/devices 也能找到这个字符设备:

 

和我们之前的驱动程序一样,但是没有使用创建设备节点,为什么?

因为需要注册了LCD驱动后,才会有设备节点,所以这里的代码没有 ,后面会分析哪里有。

2.我们来看看注册的file_operations结构体fb_fops的.open函数和.read函数,应用层是如何打开驱动、读取驱动数据

2.1 fb_open函数如下:

static int fb_open(struct inode *inode, struct file *file)
{int fbidx = iminor(inode);      //获取设备节点的次设备号struct fb_info *info;                //定义fb_info结构体int res = 0;... ...if (!(info = registered_fb[fbidx]))   //(1) info= registered_fb[fbidx],获取此设备号的lcd驱动信息try_to_load(fbidx);... ... if (info->fbops->fb_open) {          res = info->fbops->fb_open(info,1);  //调用registered_fb[fbidx]->fbops->fb_openif (res)module_put(info->fbops->owner);}return res;
}

(1) registered_fb[fbidx] 这个数组也是fb_info结构体,其中fbidx等于次设备号id,显然这个数组就是保存我们各个lcd驱动的信息

2.2 fb_read函数如下:

static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{unsigned long p = *ppos;struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode);                       //获取次设备号struct fb_info *info = registered_fb[fbidx];     //获取次设备号的lcd驱动的信息u32 *buffer, *dst;u32 __iomem *src;int c, i, cnt = 0, err = 0;unsigned long total_size;... ...if (info->fbops->fb_read)return info->fbops->fb_read(info, buf, count, ppos);total_size = info->screen_size;     //获取屏幕长度
... ...buffer
= kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,GFP_KERNEL); //分配缓冲区 if (!buffer)return -ENOMEM;src = (u32 __iomem *) (info->screen_base + p); //获取显存物理基地址if (info->fbops->fb_sync)info->fbops->fb_sync(info); while (count) {c = (count > PAGE_SIZE) ? PAGE_SIZE : count; //获取页地址dst = buffer; /*因为src是32位,一个src等于4个字节,所以页地址c >> 2*/for (i = c >> 2; i--; ) *dst++ = fb_readl(src++); //读取显存每个像素点数据,放到dst地址上if (c & 3) {u8 *dst8 = (u8 *) dst;u8 __iomem *src8 = (u8 __iomem *) src;for (i = c & 3; i--;)*dst8++ = fb_readb(src8++);src = (u32 __iomem *) src8;}if (copy_to_user(buf, buffer, c)) { //上传数据,长度等于页地址大小err = -EFAULT;break;}*ppos += c;buf += c;cnt += c;count -= c;}kfree(buffer); return (err) ? err : cnt; }

从.open和.write函数中可以发现,都依赖于fb_info帧缓冲信息结构体,它从registered_fb[fbidx]数组中得到,这个数组保存我们各个lcd驱动的信息

3.我们来找找这个数组在哪里被注册,位于register_framebuffer():

int register_framebuffer(struct fb_info *fb_info)
{... ...
for (i = 0 ; i < FB_MAX; i++)    //查找空的数组if (!registered_fb[i])break;fb_info->node = i;           ... .../*创建设备节点,名称为fdi,主设备号为29,次设备号为i   */
fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), "fb%d", i);... ...registered_fb[i] = fb_info;... ...
}

得出这个register_framebuffer()除了注册fb_info,还创建了设备节点

所以要注册驱动时就调用这个,如下图所示:

 

4.我们来看看/drivers/video/s3c2410fb.c 中又是怎么实现驱动的

4.1先找到入口出口函数:

int __devinit s3c2410fb_init(void)
{return platform_driver_register(&s3c2410fb_driver);
}static void __exit s3c2410fb_cleanup(void)
{platform_driver_unregister(&s3c2410fb_driver);
}

发现是注册、注销设备平台drv

4.2 来看看s3c2410fb_driver 如何定义的

static struct platform_driver s3c2410fb_driver = {.probe           = s3c2410fb_probe,        //检测函数,注册设备.remove         = s3c2410fb_remove,    //删除设备.suspend = s3c2410fb_suspend,          //休眠.resume          = s3c2410fb_resume,    //唤醒.driver            = {.name     = "s3c2410-lcd",           //drv名字.owner    = THIS_MODULE,},
};

和我们上节分析的platform机制一样,当与设备匹配成功,就进入probe函数,初始化驱动设备

4.3 来看看.probe函数,如何实现驱动的

static int __init s3c2410fb_probe(struct platform_device *pdev)
{struct s3c2410fb_info *info;struct fb_info     *fbinfo;struct s3c2410fb_hw *mregs;int ret;int irq;int i;u32 lcdcon1;mach_info = pdev->dev.platform_data;     //获取LCD设备信息(长宽、类型等)if (mach_info == NULL) {dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");return -EINVAL;}mregs = &mach_info->regs;irq = platform_get_irq(pdev, 0);if (irq < 0) {dev_err(&pdev->dev, "no irq for device\n");return -ENOENT;}fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); //1.分配一个fb_info结构体if (!fbinfo) {return -ENOMEM;}/*2.设置fb_info*/info = fbinfo->par;info->fb = fbinfo;info->dev = &pdev->dev;... ...    /*3.硬件相关的操作,设置中断,LCD时钟频率,显存地址, 配置引脚... ...*/ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info); //设置中断info->clk = clk_get(NULL, "lcd");                    //获取时钟clk_enable(info->clk);                                  //使能时钟ret = s3c2410fb_map_video_memory(info);               //显存地址  ret = s3c2410fb_init_registers(info);                //设置寄存器,配置引脚... ...
ret
= register_framebuffer(fbinfo); //4.注册一个fb_info结构体if (ret < 0) {printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);goto free_video_memory;} ... ... return ret; }

4.4 显然要写个LCD驱动程序,需要以下4步:

1) 分配一个fb_info结构体: framebuffer_alloc();

2) 设置fb_info

3) 硬件相关的操作(设置中断,LCD时钟频率,显存地址, 配置引脚... ...)

4 注册fb_info: register_framebuffer()

 

下节就开始如何来写LCD驱动

 (LCD驱动详解入口地址: http://www.cnblogs.com/lifexy/p/7604011.html)

转载于:https://www.cnblogs.com/lifexy/p/7603327.html

相关文章:

【牛客网】最长对称子串

给定一个字符串&#xff08;数字或大小写字母&#xff09;, 找出最长的对称的子串&#xff08;如有多个&#xff0c;输出任意一个&#xff09;。例如&#xff1a;输入&#xff1a;“abbaad”输出&#xff1a;“abba”#include <iostream> #include <cstring> #incl…

利用JS中window.showModalDialog()详解

window.showModalDialog()方法用来创建一个显示HTML内容的模态对话框。 window.showModelessDialog()方法用来创建一个显示HTML内容的非模态对话框。 使用方法&#xff1a; vReturnValue window.showModalDialog(sURL [, vArguments] [,sFeatures]) vReturnValue window.show…

数据库及页面乱码问题

目录 MySQL乱码问题 1、页面编码和文件编码 2、控制器/过滤器&#xff08;filter&#xff09; 3、数据库及表格编码 4、字符流编码 5、Tomcat编码 6、外部文件编码 MySQL乱码问题 1、页面编码和文件编码 JSP、HTML页面头部以及文件编码设置字符编码格式为UTF-8。 &…

Cornell University Designing with Microcontrollers

http://instruct1.cit.cornell.edu/courses/ee476/转载于:https://www.cnblogs.com/stoneresearch/archive/2008/10/21/4336378.html

Tomcat下载安装与环境变量的配置

注意&#xff1a;安装Tomcat之前&#xff0c;一定要先安装好JDK并正确配置jdk环境变量&#xff1b; 参考教程&#xff1a;JDK的安装与环境变量的配置 1、Tomcat下载 &#xff08;1&#xff09;百度搜索“Tomcat官网”、“Tomcat下载”等类似关键字&#xff0c;或者进入Tomcat…

[HNOI2015]落忆枫音

题目描述 不妨假设枫叶上有 n个穴位&#xff0c;穴位的编号为 1 ~ n。有若干条有向的脉络连接着这些穴位。穴位和脉络组成一个有向无环图——称之为脉络图&#xff08;例如图 1&#xff09;&#xff0c;穴位的编号使得穴位 1 没有从其他穴位连向它的脉络&#xff0c;即穴位 1 …

xp下安装sqlserver 2000的解决方案

1.在运行对话框输入&#xff1a;regedit&#xff08;注册表&#xff09; 2.把HKEY_LOCAL_MACHINE-----SYSTEM---------ControlSet001-------SessionManger--------PendingFileRenameOperations删除。转载于:https://www.cnblogs.com/deary/archive/2009/06/23/1509427.html

洛谷P2380 狗哥采矿

P2380 狗哥采矿 题目背景 又是一节平静的语文课 狗哥闲来无事&#xff0c;出来了这么一道题 题目描述 一个n*m的矩阵中&#xff0c;每个格子内有两种矿yeyenum和bloggium&#xff0c;并且知道它们在每个格子内的数量是多少。最北边有bloggium的收集站&#xff0c;最西边有 yeye…

详解DNS的常用记录(下):DNS系列之三

详解DNS常用记录&#xff08;下&#xff09;在上篇博文中我们介绍了DNS服务器中几种不可或缺的记录&#xff0c;包括A记录&#xff0c;NS记录和SOA记录。本篇博文中我们将继续为大家介绍DNS的另外几种常用记录&#xff0c;希望能对大家了解DNS有所帮助。四MX记录MX记录也被称为…

DP_knapsack

动态规划法解0-1背包问题 问题描述&#xff1a; 有n个背包&#xff0c;重量依次为w1,w2, ... ,wn, 价值依次是v1,v2, ... ,vn, 现在有一个大背包&#xff0c;其容量是capacity&#xff0c;往其中装小背包&#xff0c;要求得到的总价值最大&#xff0c;如何装&#xff1f; 用val…

三种求全排列方式之比较

一共有三种求全排列的方式&#xff1a; 第一种就是只适合用于非可重集的DFS实现 第二种就是可以用于可重集上的刘汝佳书上的代码 第三种就是STL中的next——permutation 在对这三种方式做了比较之后发现&#xff1a; DFS实现的效率最高&#xff0c;当n 10的时候耗时才不到2s&a…

Java连接数据库 JDBC

1、JDBC是什么&#xff1f; JDBC&#xff0c;英文全称&#xff1a;Java DataBase Connectivity&#xff0c;中文全称&#xff1a;java数据库连接&#xff0c;是一种用于执行SQL语句的Java API&#xff0c;可以为多种关系数据库提供统一访问&#xff0c;由一组用Java语言编写的类…

西门子smart200以太网通讯协议

西门子smart200具体的通讯文档在网上或者官网我都没有找到&#xff08;哪位大仙有请给我留言发个感激不尽&#xff09;&#xff0c;本人是通过监听控制软件分析出其中的通讯协议。 连接是通过TCP/IP协议&#xff0c;我一般喜欢用Java写测试Socket。 通讯是依照字节流沟通&#…

祝我亲爱的天蝎GG生日快乐!+相识3周年小纪念

作者&#xff1a;快乐de蚂蚁2005年10月26日我们相识于清华一教于千万人之中相遇了彼此&#xff0c;你推着车走过来&#xff0c;我站在一教门口午后温暖的阳光斑斑驳驳的洒在你身上&#xff0c;唇红齿白&#xff0c;羞涩的笑容。。。第一次见面的此情此景永远定格在我的脑海。谁…

Aspose.Words导出图片 表格 Interop.Word

先定义一个WORD 模板&#xff0c; 然后替换文本、域 &#xff0c;定位开始表格 文本和段落 // Specify font formattingAspose.Words.Font font builder.Font;font.Size 16;font.Bold true; ;font.Color Color.Black;font.Name "Arial";font.UnderlineUnderline.…

[转帖]tar高级教程:增量备份、定时备份、网络备份

tar高级教程&#xff1a;增量备份、定时备份、网络备份 作者: lesca 分类: Tutorials, Ubuntu 发布时间: 2012-03-01 11:42 ė浏览 27,065 次 61条评论一、概述 备份与恢复对于系统维护而言是至关重要的事情。不合理的备份与还原会让你的数据面临丢失的风险。许多用户都在丢失重…

C# 异步读取数据库里面的数据与绑定UI的解决办法

异步读取数据库,在数据绑定的时候会出现点问题,就是窗体界面会无法关闭,要结束任务才能结束进程。例如下面代码 首先按习惯的方法&#xff0c;设定线程更新UI a2.CheckForIllegalCrossThreadCalls false; //a2为窗体名称 下面的代码就是从数据库里取得数据并绑定 private vo…

类、抽象类、接口之间的区别

目录 1、类与抽象类的异同之处 &#xff08;1&#xff09;类和抽象类的区别 &#xff08;2&#xff09;类和抽象类的相同之处 2、接口与类的异同之处 &#xff08;1&#xff09;接口与类相似点 &#xff08;2&#xff09;接口与类的区别 &#xff08;3&#xff09;接口…

(ASA) Cisco Web ××× 配置详解 [三部曲之一]

(ASA) Cisco Web 配置详解 [三部曲之一] 注意&#xff1a;本文仅对Web特性和配置作介绍&#xff0c;不包含SSL 配置&#xff0c;SSL 配置将在本版的后续文章中进行介绍。 首先&#xff0c;先来谈一谈ASA7.X系统中的默认隧道组和组策略。ASA/PIX 7.x系统默认在show run时不显示…

IDEA和Eclipse设置文件编码格式

1、IDEA设置已有文件的编码格式 在页面右下角可以看到文件的编码方式&#xff0c;如果编码方式的图标为灰色&#xff0c;则无法修改编码格式&#xff1b;如果其颜色不是灰色且其右侧有上下方向的三角形形状&#xff0c;点击它&#xff0c;可以修改编码方式。 注意&#xff1a;该…

关于运行ssm,web请求出现HTTP415错误

HTTP415错误&#xff1a;如果controller中用到了json传值&#xff0c;那么就必须加入 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <jackson.version>2.…

堆和栈浅析【转】

引用&#xff1a; 一、预备知识—程序的内存分配一个由c/C编译的程序占用的内存分为以下几个部分1、栈区&#xff08;stack&#xff09;— 由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区&#xff…

JS-只能输入中文和英文

<span style"font-family:KaiTi_GB2312;">转自&#xff1a;<a target_blank href"http://www.cnblogs.com/liupeizhi/articles/2487472.html">http://www.cnblogs.com/liupeizhi/articles/2487472.html</a></span> </pre>&l…

SQL Server中读取XML文件的简单做法

SQL Server 2000使得以XML导出数据变得更加简单&#xff0c;但在SQL Server 2000中导入XML数据并对其进行处理则有些麻烦。本文介绍在SQL Server中读取XML文件的简单做法。SQL Server 2000使得以XML导出数据变得更加简单&#xff0c;但在SQL Server 2000中导入XML数据并对其进行…

Calling Oracle stored procedures from Microsoft.NET

摘自&#xff1a;http://www.c-sharpcorner.com/UploadFile/john_charles/CallingOraclestoredproceduresfromMicrosoftdotNET06222007142805PM/CallingOraclestoredproceduresfromMicrosoftdotNET.aspxIntroduction This article is intended to illustrate how to illustrate…

Https的底层原理

Http协议&#xff1a; 转载于:https://www.cnblogs.com/auldlangsynezh/p/10469587.html

【Linux笔记(002) 】-- centos7 文档操作基本命令

索引&#xff1a; 目录索引 一、cd -- ChangeDirectory a) 切换到 /DemoLM/ 文件夹 b) 回到用户 Home 根目录&#xff1a;是哪个账户登录的就会进入哪个用户的根目录 二、pwd -- PrintWorkingDirectory a) 查看当前工作目录 三、mkdir -- MakeDirectory a) 创建一个 /test/ 目录…

JDBC操作数据库实例

返回目录&#xff1a;《学生信息管理系统&#xff08;JavaJSP&#xff09;》 这里以JDBC操作MySQL数据库为例。 假设有一个名为test的数据库&#xff0c;里面有一张学生表&#xff0c;表名称为student&#xff0c;表结构如下&#xff1a; student表结构表中数据如下&#xff1…

面向JavaScript开发人员的Adobe AIR与Dreamweaver

入门教程&#xff0c;非常详细&#xff0c;CS4里面应该可以省略前面几步直接开发了。 Adobe AIR对于HTML/JavaScript应用程序与桌面的集成有着出色的支持&#xff0c;但除了所有附加功能之外&#xff0c;还需要一些其他工具和技术。这篇文章探讨了使用HTML/JavaScript的Web开发…

在数据显示页面增加按姓名查询功能

在上一章内容《将数据库中表格信息输出到页面上》的基础上&#xff0c;增加按姓名查询功能。 问&#xff1a;怎么在显示学生信息的页面增加按照姓名查询的功能&#xff1f; 答&#xff1a;在显示学生信息的页面&#xff0c;使用<form>标签为用户创建表单&#xff0c;表单…