第六章:字符设备

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

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. 服务器http处理流程

    网络请求.处理的组织: context Facade模式/指令处理引擎/简单处理机: 响应码: 只要有响应码就代表服务器已经接收到请求:无响应代表网络层出现问题,与服务器无关. 处理步骤: 1)模块( ...

  2. div的padding和margin

    原div一和div二的位置 增大div二的margin-left 增大div二的padding-top

  3. 用Electron开发企业网盘(二)--分片下载

    书接上文,背景见:https://www.cnblogs.com/shawnyung/p/10060119.html HTTP请求头  Range 请求资源的部分内容(不包括响应头的大小),单位是by ...

  4. ip代理池的爬虫编写、验证和维护

    打算法比赛有点累,比赛之余写点小项目来提升一下工程能力.顺便陶冶一下情操 本来是想买一个服务器写个博客或者是弄个什么FQ的东西 最后刷知乎看到有一个很有意思的项目,就是维护一个「高可用低延迟的高匿IP ...

  5. 【转】NPOI使用手册

    [转]NPOI使用手册 NPOI使用手册 目录 1.认识NPOI 2. 使用NPOI生成xls文件 2.1 创建基本内容 2.1.1创建Workbook和Sheet 2.1.2创建DocumentSu ...

  6. 洛谷 P1171 售货员的难题

    P1171 售货员的难题 题目背景 数据有更改 题目描述 某乡有n个村庄(1<n<20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且 ...

  7. Linux同步与相互排斥应用(零):基础概念

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]         当操作系统进入多道批处理系统时 ...

  8. IOS开发之蘑菇街框架

    近期公司的项目全然仿了蘑菇街client的框架,自己从网上找了一下,没有发现源代码.问遍各大QQ群也没有结果.上周五晚上一直在思考这个框架怎样搭建,周六早上有了灵感.写了一半.今天接着完好了一下. 在 ...

  9. !HDU 2602 Bone Collector--DP--(裸01背包)

    题意:这题就是一个纯粹的裸01背包 分析:WA了好几次.01背包实现的一些细节没搞懂 1.为什么dp[i][j]赋初值为0而不是value[i].由于第i个石头可能不放! 2.在进行状态转移之前要dp ...

  10. JAVA并发--volatile

    学过计算机组成原理的一定知道,为了解决内存速度跟不上CPU速度这个问题,在CPU的设计中加入了缓存机制,缓存的速度介于CPU和主存之间.在进行运算的时候,CPU将需要的数据映射一份在缓存中,然后直接操 ...