学习笔记——《linux设备驱动程序(第三版)》linux设备模型:内核添加删除设备驱动程序(代码片段)

贺二公子 贺二公子     2022-10-23     108

关键词:

文章目录

以下为阅读《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. 调用 device_register(&xxx_driver->device_driver) 将 xxx 驱动程序添加到驱动核心中。

关于device_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 被解开,模块就要保留在内核中。

javascript高级程序设计(第三版)学习笔记111217章

第11章, DOM扩展选择符 APISelectorAPILevel1核心方法querySelector 、querySelectorAll,兼容的浏览器可以使用 Document,Element 实例调用它们,支持浏览器:IE8+,Firefox3.5+,Safari3.1+,chrome,Opera10+querySelector方法接收一个& 查看详情

javascript高级程序设计(第三版)学习笔记8910章

第8章,BOMBOM的核心对象是window,具有双重角色,既是js访问浏览器的一个接口,又是ECMAScript规定的Global对象。因此,在全局作用域中声明的函数、变量都会变成window对象的属性和方法。例:varage=20;functionsayAge(){alert(this.age);}alert(... 查看详情

javascript高级程序设计(第三版)学习笔记1314章

第13章,事件事件冒泡IE的事件叫做事件冒泡:由具体到不具体<!DOCTYPEhtml><html><head>   <title>EventBubblingExample</title></head><body>   <divid="myDiv"& 查看详情

javascript高级程序设计(第三版)学习笔记202123章

第20章,JSONJSON(JavaScriptObjectNotation,JavaScript对象表示法),是JavaScript的一个严格的子集。JSON可表示一下三种类型值:简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined对象:一组无序的键值对数组:一组有序的... 查看详情

javascript高级程序设计(第三版)学习笔记222425章

第22章,高级技巧高级函数安全的类型检测typeof会出现无法预知的行为instanceof在多个全局作用域中并不能正确工作调用Object原生的toString方法,会返回[ObjectNativeConstructorName]格式字符串。每个类内部都有一个[[Class]]属性,这个属... 查看详情

javascript高级程序设计(第三版)学习笔记1~5章

第2章,在html中使用JavaScriptHtml引入外部js脚本<scripttype="text/javascript"src="test.js">两个</script>之间不应放脚本,因为并不会被执行</script><script>标签有一个defer属性可以延迟脚本执行,但是并不保证会按脚本排列顺... 查看详情

linux设备驱动开发详解第三版啥时候出

参考技术A  《Linux设备驱动开发详解(第3版)》的最新进展。  2014.8.22目前初步完成2-11章以及第22章《Linux设备驱动的调试》,相对于第2版,这几章主要的变更。  [F]是修正或升级;[N]是新增知识点;[D]是删除的内容  第... 查看详情

《qt5开发与实例(第三版)》学习笔记

1//4.1Qt5基本对话框2//创建一个带有对话框的程序的一般步骤:3//1创建工程4//在自定义类的头文件中:5//2声明要用到的组件6QPushButton*fileBtn;7QLineEdit*fileLineEdit;8//3添加槽函数,主要用于处理当你点击某个按钮时弹出对话框;处理对... 查看详情

鸟哥的linux私房菜基础篇-第三版笔记

第三章主机规划于磁盘分区IDE硬盘机        /dev/hd[a-d]SCSI/SATA/USB     /dev/sd[a-p]USB快闪碟        /dev/sd[a-p](与SATA相同)软盘驱动器        /dev/fd[0-1]打印机          25针:/dev/... 查看详情

《qt5开发与实例(第三版)》学习笔记

1//4.2Qt5自定义对话框2#include<QMessageBox>34voidDialog::showCustomMsgBox()5{6QMessageBoxcustomMsgBox;//新建一个自定义消息对话框对象7customMsgBox.setWindowTitle(tr("title"));//设置对话框的标题8QPushButton*yesBtn=customMsgB 查看详情

《qt5开发与实例(第三版)》学习笔记

1//3.3堆栈窗体QStackedWidget类2//stackdlg.h3#ifndefSTACKDLG_H4#defineSTACKDLG_H56#include<QDialog>7#include<QListWidget>8#include<QStackedWidget>9#include<QLabel>10classStackDlg:pub 查看详情

《qt5开发与实例(第三版)》学习笔记

1//3.1分割窗口QSplitter类2#include"mainwindow.h"3#include<QApplication>4#include<QSplitter>5#include<QTextEdit>6intmain(intargc,char*argv[])7{8QApplicationa(argc,argv);9QFontfont("ZYSong1 查看详情

《qt5开发与实例(第三版)》学习笔记

1//2.5控件2//2.51按钮组(Buttons)3/*4RadioButton//单选按钮5CheckBox//复选框6DialogButtonBox//对话框按钮盒7*/8//main.cpp9#include"mywidget.h"10#include<QApplication>1112intmain(intargc,char*argv[])13{14QApplication 查看详情

《qt5开发与实例(第三版)》学习笔记

1//3.4基本布局(QLayout)2//dialog.h3#ifndefDIALOG_H4#defineDIALOG_H56#include<QDialog>7#include<QLabel>8#include<QLineEdit>9#include<QComboBox>10#include<QTextEdit>11#include& 查看详情

《qt5开发与实例(第三版)》学习笔记

1//3.5『综合实例』修改用户资料2//main.cpp3#include"content.h"4#include<QApplication>5#include<QTextCodec>6#include<QSplitter>7#include<QListWidget>8intmain(intargc,char*argv[])9{10QApplica 查看详情

css3秘笈第三版涵盖html5学习笔记13~17章

第13章,构建基于浮动的布局使用的是float(浮动)属性注:float:none值将取消所有浮动,通常只用来取消元素中已经应用的浮动。切记:不需要给正文的div设计宽度,即使设计成固定宽度也不用用浮动进行布局LayoutGala网站(http:/... 查看详情

《css3秘籍》(第三版)-读书笔记

第12章 CSS页面布局网页布局的类型:固定宽度。不管浏览器窗口的宽度多大,网页内容的宽度始终保持不变。流式。流式设计采用百分比,它会根据浏览器的宽度(无论有多宽)自动进行调整。网页会随着访问者调整浏览器... 查看详情

javascript高级程序设计学习笔记01章javascript的认知

...上好,所谓一年之计在于春,一日之计在于晨。今天开始学习高级程序设计第三版第二遍以前以迅雷不及掩耳之势草草看过一遍,但是什么也没记住已经忘得差不多了。哈哈,原来我不是黄蓉,也不是天才,还是那句话好记性不... 查看详情