文章目录

  • 1. 前言
  • 2. 准备工作
    • 2.1. 概念
    • 2.2. 具体总线、设备、驱动结构体说明
    • 2.3. 注册总线
  • 3. 添加设备
    • 3.1. STEP1 ——发现设备并创建设备结构 struct XXX_dev
    • 3.2. STEP2 ——初始化设备结构
    • 3.3. STEP3 ——注册设备
  • 4. 删除设备
  • 5. 添加驱动程序
  • 6. 删除驱动程序

以下为阅读《LINUX设备驱动程序(第三版)》一书第十四章Linux设备模型时的部分内容总结(就是翻译的通俗点,让我自己以后需要复习时能看得容易点),可能有错误或遗漏,请参照原书原文,或留言指正,thanks。

1. 前言

该章先讲解了设备驱动的几个基础概念:kobject、kset、subsystem、sysfs、hotplug、bus、device、device_drive、class。

本文主要总结内核添加设备和删除设备的过程。

2. 准备工作

2.1. 概念

//总线结构
struct bus_type{char *name;struct sybsystem subsys;struct kset drivers;struct kset devices;int (*match)(struct device *dev, struct device driver *drv);struct device *(*add)(struct device *parent, char *bus_id);int (*hotplug)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);......
}
//设备结构
struct device{struct device *parent;struct kobject kobj;char bus_id[BUS_ID_SIZE];struct bus_type *bus;struct device_driver *driver;void *driver_data;void (*release)(struct device *dev);......
}
//驱动结构
struct device_driver{char *name;struct bus_type *bus;struct kobject kobj;struct list_head devices;int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);......
}

2.2. 具体总线、设备、驱动结构体说明

内核中对具体的总线、设备、驱动定义了相应的结构体类型,以 PCI 为例。struct pci_dev 与 struct device 的关系类似于面向对象中的子类与父类的关系。例如,

//总线结构
struct bus_type{char *name;struct sybsystem subsys;struct kset drivers;struct kset devices;int (*match)(struct device *dev, struct device driver *drv);struct device *(*add)(struct device *parent, char *bus_id);int (*hotplug)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);......
}

其中,struct pci_driver 是 struct device_driver 的扩展结构,两者间关系与 pci_dev 与 device 关系类似。

针对 pci 设备,定义 struct pci_bus_type 用于描述 pci 总线结构,它相当于 struct bus_type 的扩展结构。详情参照原书。

为了方便说明,进行以下说明:

  • struct xxx_dev 为注册到 xxx 总线的设备对 struct device 结构的扩展结构
  • struct xxx_driver 为注册到 xxx 总线的驱动程序对 struct device_driver 结构的扩展结构
  • xxx_bus_type 为 xxx 总线的 bus_type 结构变量。
  • 其他以 xxx_ 开头的函数均为用于实现 xxx 总线相关功能的函数。

2.3. 注册总线

驱动程序或设备的初始化时,其结构体 struct device_driver 和 struct device 中的总线类型指针 struct bus_type *bus 需要指向各自挂载的总线结构。

因此,内核添加设备前,需要先注册总线类型,通过调用 bus_register() 可实现。

3. 添加设备

3.1. STEP1 ——发现设备并创建设备结构 struct XXX_dev

当内核在某总线上发现新设备时,创建与总线相关的设备结构 struct xxx_dev。

3.2. STEP2 ——初始化设备结构

这里主要初始化了 xxx_dev->device 结构。其中:

  • xxx_dev->device->parent 设置为该设备所在的总线设备或宿主控制器设备;
  • xxx_dev->device->bus 设置为指向设备挂载的总线结构 bus_type 的变量,例如注册到 pci 总线的设备设置为 &pci_bus_type。

3.3. STEP3 ——注册设备

注册设备设备使用 device_register(&xxx_dev),该函数通过以下操作实现对设备的初始化:

  1. 驱动核心对 struct device 中的许多成员进行初始化。
  2. 向 kobject 核心注册该设备的 kobject。
  3. 该设备被添加到包含该设备的父节点(device->parent)的设备列表中。
  4. 该设备被添加到与总线相关的所有设备链表(device->bus->devices)中,该链表包含了所有注册到该总线的设备。
  5. 遍历总线上注册的驱动程序,依次调用总线的 bus_type->match() 函数(该函数流程后续说明),查看该驱动程序是否支持当前设备。
  6. 若步骤5 返回 0,说明该驱动程序不支持当前设备,重复步骤 5。
  7. 若步骤5 返回 1,说明该驱动程序支持当前设备。
  8. 驱动核心将当前设备的 device->driver 指向该驱动,并调用该驱动程序的 device_driver->probe() 函数(该函数流程后续说明),查看该驱动该驱动能否处理当前设备。
  9. 若步骤8 返回非 0 的错误信息,说明该驱动程序不能处理当前设备,则重复步骤 5。
    10.若步骤 8 返回 0,说明该驱动程序能处理当前设备。
  10. 将当前设备添加到该驱动的设备链表(device_driver->devices)中,并 sysfs 中将该驱动程序目录和当前设备之间建立符号链接。

关于bus_type->match()。注册总线前,将bus_type->match()函数指定为 xxx_bus_match()。其实现功能如下:

  1. 将参数 struct device 结构转换为 struct xxx_dev 结构。
  2. 将参数 struct device_driver 结构转换为struct xxx_driver结构。
  3. 查看struct xxx_dev 和struct xxx_driver 中的相关信息,以确定当前驱动程序是否支持当前设备。
  4. 若当前驱动程序与当前设备不匹配,match() 向驱动核心返回0;否则,返回1。

关于 device_driver->probe()。注册驱动程序前,将 device_driver->probe() 函数值定位 xxx_device_probe()。实现功能如下:

  1. 将参数 struct device 结构转换为 struct xxx_dev 结构。
  2. 将 device->driver 结构转换为 struct xxx_driver 结构。
  3. 检测当前驱动程序的状态,确保能支持这个函数(用绑定的 xxx_dev 结构指针为参数调用 xxx_driver->probe()),增加设备的引用计数。
  4. 若 xxx_driver->probe() 判定不能处理当前设备,则返回负的错误之给驱动核心;否则,返回 0。

4. 删除设备

删除设备调用 xxx_remove_bus_device() 函数,该函数进行以下操作:

  1. 进行清理工作。
  2. 使用 xxx_dev->device 作为参数调用 device_unregister() 函数。
    当 xxx_remove_bus_device() 函数结束后,若该设备的 kobject 已经不被引用,调用 xxx_release_dev() 函数,释放 xxx_dev 结构占用的空间。

关于 device_unregister() 。实现功能如下:

  1. 删除了 sysfs 中从设备绑定的驱动程序到设备之间的符号链接。
  2. 将该设备从设备绑定的驱动程序的设备链表中删除。
  3. 使用 device->kobject 作为参数调用 kobject_del()。

关于 kobject_del()。实现功能如下:

  1. 引起用户空间 hotplug 的调用。
  2. 删除全部与 kobject 相关的 sysfs 文件、目录。
  3. 删除设备的 kobject 的引用。

5. 添加驱动程序

添加驱动调用xxx_register_driver()函数,该函数进行以下操作:

  1. 初始化 xxx_driver->device_driver 结构体。
  2. 调用 driver_register(&xxx_driver->device_driver) 将 xxx 驱动程序添加到驱动核心中。

关于driver_register()。实现功能如下:

  1. 初始化 device_driver 中的锁。
  2. 调用 bus_add_driver(),函数功能如下。

关于 bus_add_driver()。实现功能如下:

  1. 查找与驱动程序相关的总线。若未找到,则函数返回。
  2. 根据驱动程序的名字以及相关的总线,创建驱动程序的 sysfs 目录。
  3. 获取总线内部的锁,遍历所有向总线注册的设备,参照 3.3 节的 bus_type->match(),依次为其调用 match 函数。

6. 删除驱动程序

删除驱动调用 xxx_unregister_driver() 函数,该函数执行以下操作:
调用 driver_unregister(&xxx_driver->device_driver)

关于 driver_unregister() 函数。实现功能如下:

  1. 清除 sysfs 中属于驱动程序的 sysfs 属性。
  2. 遍历驱动程序设备列表,参照 4 节,依次调用 release 函数。
  3. 执行以下操作:
    • down(&drv->unload_sem);
    • up(&drv->unload_sem);
    • 原因:函数安全返回前,代码需要等待驱动所有调用引用技术清零。
    • 只要驱动程序正被设备所引用并等待 unload->sem 被解开,模块就要保留在内核中。

学习笔记——《LINUX设备驱动程序(第三版)》Linux设备模型:内核添加、删除设备、驱动程序相关推荐

  1. 【Java学习笔记】55:JDBC-MySQL基本使用,游标控制,CONCUR_UPDATABLE,更新/添加/删除

    配置了这么久终于可以学习JDBC了,在这之前,给刚刚的表多插入一些表项: mysql> USE newDB; Database changed mysql> INSERT INTO New ...

  2. Linux设备驱动程序 第三版 读书笔记(一)

    Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...

  3. LINUX设备驱动程序第三版.pdf,linux设备驱动程序第3版.pdf免费下载链接,学习资源下载

    LINUX设备驱动程序第三版.pdf免费下载链接(.pdf书籍的优点是便于直接在电脑中保存有电脑就可以阅读,如果觉得这本书给你提供到了很大的帮助,可以去书店补一本纸质版) 资源保存在腾讯微云上,下载不 ...

  4. R语言学习笔记——入门篇:第三章-图形初阶

    R语言 R语言学习笔记--入门篇:第三章-图形初阶 文章目录 R语言 一.使用图形 1.1.基础绘图函数:plot( ) 1.2.图形控制函数:dev( ) 补充--直方图函数:hist( ) 补充- ...

  5. MySQL学习笔记——尚硅谷李玉婷经典版MySQL基础笔记(一)

    MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) MySQL学习笔记目录 MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) 一.基础知识 1.MySQL的语法规范 2. ...

  6. 大数据Hadoop教程-学习笔记01【大数据导论与Linux基础】

    视频教程:哔哩哔哩网站:黑马大数据Hadoop入门视频教程,总时长:14:22:04 教程资源:https://pan.baidu.com/s/1WYgyI3KgbzKzFD639lA-_g,提取码: ...

  7. 机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计

    机器人学中的状态估计学习笔记(二)第三章线性高斯系统的状态估计 3.1 离散时间的批量估计问题 3.1.1 问题定义 3.1.2 最大后验估计 3.1.3 贝叶斯推断 3.1.4 存在性.唯一性与能观 ...

  8. 机器学习理论《统计学习方法》学习笔记:第六章 逻辑斯谛回归与最大熵模型

    机器学习理论<统计学习方法>学习笔记:第六章 逻辑斯谛回归与最大熵模型 6 逻辑斯谛回归与最大熵模型 6.1 逻辑斯谛回归模型 6.1.1 逻辑斯谛分布 6.1.2 二项逻辑斯蒂回归模型 ...

  9. 动手深度学习笔记(四十五)8.1. 序列模型

    动手深度学习笔记(四十五)8.1. 序列模型 8.1. 序列模型 8.1.1. 统计工具 8.1.1.1. 自回归模型 8.1.1.2. 马尔可夫模型 8.1.1.3. 因果关系 8.1.2. 训练 ...

  10. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记--async和await(一) 接上文 多线程编程学习笔记--async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

最新文章

  1. 使用python中的库matplotlib绘制箱线图(boxplot)
  2. Hadoop MapReduce编程 API入门系列之最短路径(十五)
  3. Django 3.2.5博客开发教程:URL与视图函数
  4. python关系图谱_文本分析之制作网络关系图
  5. python中for和while可以有else_Python 中的for,if-else和while语句
  6. Coursera Machine Leaning 课程总结
  7. IT人必去的几大网站,国内外知名IT网站罗列!
  8. python实战===用python识别图片中的中文
  9. U盘做启动盘之后容量变小
  10. cms php vue 开源_2020最受欢迎的企业网站CMS建站系统排行榜
  11. js判断移动端或是pc端
  12. 智慧体育训练考核系统软件-智能体能综合测评系统
  13. java 字符转换为字符串_java中将字符(Char)转换为字符串的四种方式
  14. ubuntu16.04安装NVIDIA显卡驱动
  15. 文档损坏了怎么修复?文档修复方法分享
  16. matlab 读取mdf文件路径,通过 MDF 数据存储使用 MDF 文件
  17. mapper找不到报错:Field xxxMapper in xxx required a bean of type 'xxxMapper' that could not be found
  18. 什么是Power BI?
  19. 下载excel表格后缀名为.do形式
  20. 和平精英显示模拟服务器已满,和平精英模拟器注册已经达到了上限怎么办?原因及解决方法分享...

热门文章

  1. 华为鸿蒙和海思,华为鸿蒙+海思,值得你期待!
  2. 新闻api接口 关键字检索最新新闻动态
  3. Anaconda 的安装教程(图文)
  4. 《人生的智慧》读后感
  5. 沃尔玛卡批量绑卡绑定软件工具助手
  6. 招商银行信用卡中心测试工程师校招面经
  7. HDU 1686 [KMP] --by二汪
  8. java.lang.NoClassDefFoundError: com.google.gson.Gson
  9. Kotlin——高阶函数详解与标准的高阶函数使用
  10. 永磁同步电机的FOC/ DTC控制比较