第六章:字符设备

申请设备号---注册设备

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驱动开发入门与实战》的更多相关文章

  1. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  2. 【转】linux驱动开发的经典书籍

    原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书 ...

  3. 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  4. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  5. s3c6410 Linux 驱动开发环境搭建

    s3c6410 Linux 驱动开发环境搭建 -- 既然你是做Linux开发的,你还用虚拟机? 非常多人都在win下做开发,于是SD_writer.exe之类的烧写工具"大行其道" ...

  6. linux驱动开发的经典书籍

    转载于:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html 参加实习也近一个月了,严重感觉知识不够,真是后悔学校里浪费那么 ...

  7. 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 ...

  8. 转:linux驱动开发的经典书籍

    源地址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书为 ...

  9. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

随机推荐

  1. tensorboard 使用

    TensorBoard是TensorFlow 的可视化工具.主要为了更方便用户理解 TensorFlow 程序.调试与优化,用户可以用 TensorBoard 来展现 TensorFlow 图像,绘制 ...

  2. php 自带加密函数 mcrypt_encrypt

    <?php /** * AES128加解密类 * @author dy * */ class Aes{ //密钥 private $_secrect_key; public function _ ...

  3. NodeJS学习笔记 (16)子进程-child_process(ok)

    原文: https://github.com/chyingp/nodejs-learning-guide/blob/master/README.md 自己的跟进学习: 父进程,子进程,线程之间的关系 ...

  4. [POI2008]KUP-Plot purchase(单调队列)

    题意 给定k,n,和n*n的矩阵,求一个子矩形满足权值和在[k,2k]之间 , 题解 这里用到了极大化矩阵的思想.推荐论文<浅谈用极大化思想解决最大子矩阵问题>Orz 如果有一个元素在[k ...

  5. minixml的安装教程

    最近想要实现对xml的解析,上网看到有很多库可以直接调用,例如minixml,tinyxml等,我选择了minixml(没有原因,纯属是因为这个找到了中文文档- -) 附上中文文档链接:https:/ ...

  6. Hadoop学习总结(1)——大数据以及Hadoop相关概念介绍

    一.大数据的基本概念 1.1.什么是大数据 大数据指的就是要处理的数据是TB级别以上的数据.大数据是以TB级别起步的.在计算机当中,存放到硬盘上面的文件都会占用一定的存储空间,例如: 文件占用的存储空 ...

  7. POJ 1035-Spell checker(字符串)

    题目地址:POJ 1035 题意:输入一部字典.输入若干单词. 若某个单词能在字典中找到,则输出corret.若某个单词能通过 变换 或 删除 或 加入一个字符后.在字典中找得到.则输出这些单词.输出 ...

  8. uvalive 6669 hidden tree(好壮压dp)

    题目见option=com_onlinejudge&Itemid=8&page=show_problem&problem=4681">here 题意:给一个序列 ...

  9. Unity UGUI——UI基础,Canvas

    主题:画布--Canvas 内容:创建Canvas UI控件的绘制顺序 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTXJfQUhhbw==/font/5 ...

  10. Beta分布从入门到精通

    近期一直有点小忙,可是不知道在瞎忙什么,最终有时间把Beta分布的整理弄完. 以下的内容.夹杂着英文和中文,呵呵- Beta Distribution Beta Distribution Defini ...