2019.05.08 《Linux驱动开发入门与实战》
第六章:字符设备
申请设备号---注册设备
1、字符设备的框架:
2、结构体,struct cdev:
3、字符设备的组成:
4、例子:
5、申请和释放设备号:
设备号和设备节点是什么关系。?
设备驱动中,很多功能是通过设备号完成的。
步骤:
构建字符设备前,应该申请设备号:所用到的函数是下面两个:
该函数在<fs/char_dev.c>中定义
int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor,unsigned count, const char *name) ;
释放设备号,统一使用下面的函数,通常在模块的卸载函数中会调用这个。
void unregister_chrdev_region(dev_t from, unsigned count);
申请字符设备的设备号后,需要将字符设备注册到系统中。这样才能使用字符设备。
为了实现这个过程,需要先解释cdev结构体。cdev结构体描述字符设备,该结构体是
所有字符设备的抽象,其包含了大量字符设备所共有的特性。
cdev中kobj成员,用于内核管理字符设备,驱动开发基本不用。
cdev中ops指向的file_operations结构的指针,该结构定义了操作字符设备的函数。
cdev中dev是用来存储字符设备所申请的设备号。
cdev中count表示目前有多少个字符设备在使用改启动程序。
cdev中list是一个双向链表,用于将其他结构体链接成一个双向链表。这种结构在linux中常用,需要掌握。
每一个字符设备在/dev目录下都有一个设备文件,打开设备文件就相当于打开相应的字
符设备。例如应用程序打开设备文件A,那么系统会产生一个inode结点。这样可以通过
inode结点的i_cdev字段找到cdev字符结构体。通过cdev的ops指针,就能找到设备A的
操作函数。对操作函数的讲解,将放在后面的内容中。
file_operations是一个对设备进行操作的抽象结构体。Linux内核的设计非常巧妙。内
核允许为设备建立一个设备文件,对设备文件的所有操作,就相当于对设备的操作。这
样的好处是,用户程序可以使用访问普通文件的方法访问设备文件,进而访问设备。这
样的方法,极大地减轻了程序员的编程负担,程序员不必去熟悉新的驱动接口,就能够
访问设备。
对普通文件的访问常常使用open()、read()、write()、close()、ioctl()等方法。同
样对设备文件的访问,也可以使用这些方法。这些调用最终会引起对
file_operations结构体中对应函数的调用。对于程序员来说,只要为不同的设备编写
不同的操作函数就可以了。
为了使file_operations结构体具有通用性,file_operations会不断地扩充,现在已经非常
庞大,只需要对file_operations结构体中几个重要的成员进行分析:
owner成员根本不是一个函数;它是一个指向拥有这个结构模块的指针。这个成员用来
维持模块的引用计数,当模块还在使用时,不能用rmmod卸载模块。几乎所有时刻,它
被简单初始化为 THIS_MODULE,一个在<linux/module.h>中定义的宏。
llseek()函数用来改变文件中的当前读/写位置,并将新位置返回。loff_t参数是一个
"long long"类型,"long long"类型即使在32位机上也是64位宽。这是为了与64位机兼
容而定的,因为64位机的文件大小完全可以突破4G。
read()函数用来从设备中获取数据,成功时函数返回读取的字节数,失败时返回一个负
的错误码。
write()函数用来写数据到设备中。成功时该函数返回写入的字节数,失败时返回一个
负的错误码。
ioctl()函数提供了一种执行设备特定命令的方法。例如使设备复位,这既不是读操作
也不是写操作,不适合用read()和write()方法来实现。如果在应用程序中给ioctl传入
没有定义的命令,那么将返回-ENOTTY的错误,表示该设备不支持这个命令。
open()函数用来打开一个设备,在该函数中可以对设备进行初始化。如果这个函数被复
制NULL,那么设备打开永远成功,并不会对设备产生影响。
release()函数用来释放open()函数中申请的资源,将在文件引用计数为0时,被系统调
用。其对应应用程序的close()方法,但并不是每一次调用close()方法,都会触发
release()函数,在对设备文件的所有打开都释放后,才会被调用。
一般来说,驱动开发人员会将特定设备的特定数据放到cdev结构体后,组成一个新的结
构体。如图6.3所示,"自定义字符设备"中就包含特定设备的数据。该"自定义设备"中
有一个cdev结构体。cdev结构体中有一个指向file_operations的指针。这里
,file_operations中的函数就可以用来操作硬件,或者"自定义字符设备"中的其他数
据,从而起到控制设备的作用。
inode结构体 【这个可以理解为设备节点?】
内核使用inode结构在系统内部表示文件。inode一般作为file_operations结构中函数的参
数传递过来。例如,open()函数将传递一个inode指针进来,表示目前打开的文件结点
。需要注意的是,inode的成员已经被系统赋予了合适的值,驱动程序只需要使用该结
点中的信息,而不用更改。Oepn()函数为:int (*open) (struct inode *, struct file *);
inode结构中包含大量的有关文件的信息。这里,只对编写驱动程序有用的字段进行介
绍,对于该结构更多的信息,可以参看内核源码。
dev_t i_rdev,表示设备文件对应的设备号。
struct list_head i_devices,如图6.2所示,该成员使设备文件连接到对应的cdev结
构,从而对应到自己的驱动程序。
struct cdev *i_cdev,如图6.2所示,该成员也指向cdev设备。
除了从dev_t得到主设备号和次设备号外,这里还可以使用imajor()和iminor()函数从
i_rdev中得到主设备号和次设备号。
在Linux系统中,字符设备驱动程序由以下几个部分组成。
字符设备加载和卸载函数
在字符设备的加载函数中,应该实现字符设备号的申请和cdev的注册。相反,在字符设
备的卸载函数中应该实现字符设备号的释放和cdev的注销。
cdev是内核开发者对字符设备的一个抽象。除了cdev中的信息外,特定的字符设备还需
要特定的信息,常常将特定的信息放在cdev之后,形成一个设备结构体,如代码中的
xxx_dev。
file_operations结构体和其成员函数
驱动程序与应用程序的数据交换
字符设备是3大类设备(字符设备、块设备、网络设备)中较简单的一类设备,其驱动
程序中完成的主要工作是初始化、添加和删除cdev结构体,申请和释放设备号,以及填
充file_operation结构体中操作函数,并实现file_operations结构体中的read()、
write()、ioctl()等重要函数。如图6.4所示为cdev结构体、file_operations和用户空
间调用驱动的关系。
2019.05.08 《Linux驱动开发入门与实战》的更多相关文章
- 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- 【转】linux驱动开发的经典书籍
原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书 ...
- 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- s3c6410 Linux 驱动开发环境搭建
s3c6410 Linux 驱动开发环境搭建 -- 既然你是做Linux开发的,你还用虚拟机? 非常多人都在win下做开发,于是SD_writer.exe之类的烧写工具"大行其道" ...
- linux驱动开发的经典书籍
转载于:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html 参加实习也近一个月了,严重感觉知识不够,真是后悔学校里浪费那么 ...
- Heartbeat took longer than "00:00:01" at "09/06/2019 05:08:08 +00:00".
.netcore在k8s+docker+linux,部署后,偶尔会报这样的警告 Warn:Microsoft.AspNetCore.Server.KestrelHeartbeat took longe ...
- 转:linux驱动开发的经典书籍
源地址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书为 ...
- 嵌入式Linux驱动开发日记
嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...
随机推荐
- tensorboard 使用
TensorBoard是TensorFlow 的可视化工具.主要为了更方便用户理解 TensorFlow 程序.调试与优化,用户可以用 TensorBoard 来展现 TensorFlow 图像,绘制 ...
- php 自带加密函数 mcrypt_encrypt
<?php /** * AES128加解密类 * @author dy * */ class Aes{ //密钥 private $_secrect_key; public function _ ...
- NodeJS学习笔记 (16)子进程-child_process(ok)
原文: https://github.com/chyingp/nodejs-learning-guide/blob/master/README.md 自己的跟进学习: 父进程,子进程,线程之间的关系 ...
- [POI2008]KUP-Plot purchase(单调队列)
题意 给定k,n,和n*n的矩阵,求一个子矩形满足权值和在[k,2k]之间 , 题解 这里用到了极大化矩阵的思想.推荐论文<浅谈用极大化思想解决最大子矩阵问题>Orz 如果有一个元素在[k ...
- minixml的安装教程
最近想要实现对xml的解析,上网看到有很多库可以直接调用,例如minixml,tinyxml等,我选择了minixml(没有原因,纯属是因为这个找到了中文文档- -) 附上中文文档链接:https:/ ...
- Hadoop学习总结(1)——大数据以及Hadoop相关概念介绍
一.大数据的基本概念 1.1.什么是大数据 大数据指的就是要处理的数据是TB级别以上的数据.大数据是以TB级别起步的.在计算机当中,存放到硬盘上面的文件都会占用一定的存储空间,例如: 文件占用的存储空 ...
- POJ 1035-Spell checker(字符串)
题目地址:POJ 1035 题意:输入一部字典.输入若干单词. 若某个单词能在字典中找到,则输出corret.若某个单词能通过 变换 或 删除 或 加入一个字符后.在字典中找得到.则输出这些单词.输出 ...
- uvalive 6669 hidden tree(好壮压dp)
题目见option=com_onlinejudge&Itemid=8&page=show_problem&problem=4681">here 题意:给一个序列 ...
- Unity UGUI——UI基础,Canvas
主题:画布--Canvas 内容:创建Canvas UI控件的绘制顺序 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTXJfQUhhbw==/font/5 ...
- Beta分布从入门到精通
近期一直有点小忙,可是不知道在瞎忙什么,最终有时间把Beta分布的整理弄完. 以下的内容.夹杂着英文和中文,呵呵- Beta Distribution Beta Distribution Defini ...