一、设备类型

1. Unix系统

- 块设备
- 字符设备
- 网络设备

2. 块设备

  • 通常缩写为blkdev,它是可寻址的,寻址以块为单位,块大小随设备不同而不同;块设备通常支持重定位操作,也就是对数据的随机访问。
  • 块设备是通过称为“块设备节点”的特殊文件来访问的,井且通常被挂载为文件系统。

3. 字符设备

  • 通常缩写为cdev,它是不可寻址的,仅提供数据的流式访问,就是一个个字符,或者一个个字节。
  • 字符设备的例子有键盘、鼠标、打印机,还有大部分伪设备。字符设备是通过称为“字符设备节点”的特殊文件来访问的。与块设备不同,应用程序通过直接访问设备节点与字符设备交互。

4. 网络设备

  • 最常见的类型有时也以以太网设备称呼,它提供了对网络〈例如Internet)的访问,这是通过-个物理适配器和一种特定的协议进行的
  • 网络设备打破了Unix的“所有东西都是文件”的设计原则,它不是通过设备节点来访问,而是通过套接字API这样的特殊接口来访问。

5. 伪设备

大部分设备驱动是表示物理设备的,但并不是所有设备驱动都表示物理设备。有些设备驱动是虚拟的,仅提供访问内核功能而已。我们称为“伪设备”。

常见的如:

  • 内核随机数发生器(通过/dev/random和/dev/urandom 访问)
  • 空设备(通过/dev/null 访问)
  • 零设备(通过/dev/zero 访问)
  • 满设备(通过/dev/full 访问)
  • 内存设备(通过/dev/mem 访问)

二、模块

1. 概述

  • Linux 内核是模块化组成的,它允许内核在运行时动态地向其中插入或从中删除代码。这些代码(包括相关的子例程、数据、函数人口和函数出口〉被一并组合在一个单独的二进制镜像中,即所谓的可装载内核模块中,或简称为模块。

  • 支持模块的好处是基本内核镜像可以尽可能地小,因为可选的功能和驱动程序可以利用模块形式再提供。模块允许我们方便地删除和重新载入内核代码,也方便了调试工作。而且当热插拔新设备时,可通过命令载入新的驱动程序。

      模块的所有初始化函数必须符合形式:int my _ init (void);
      退出函数必须符合形式:void my_exit (void);
    

2. 构建与安装

  • 安装编译的模块: make modules_install

  • 产生依赖关系信息,而且在每次启动时更新。

      产生内核依赖关系的信息(root):depmod
      只为新模块生成依赖信息,不生成所有的依赖关系(root):depmod -A
    
  • 载入

      (root):insmod module .ko
    
  • 在内核via modprobe中插入模块

      (root):zmodprobe module[module parameters] (参数 module 指定了需要载入的模块各称)。
    
  • 从内核中卸载模块:

      (root):modprobe -r modules
    

3. 管理配置选项

  • 设置CONFIG_FISHING_POLE 配置选项。
  • 如果建立了一个新子目录,希望kconfig 文件(可能是drivers/char/Kconfig)存在子该目录中,在己存在的 kconfig 文件中将它引入:source "drivers/char/fishing/Kcor,lfig”

4. 参数

  • 定义一个模块参数可通过宏完成:module_param(name, type, perm)。
  • 参数的类型可以是byte 、short 、ushort、int、uint、long 、ulong、charp、bool 或invbool。

5. 导出符号表

  • 导出内核函数需要使用特殊的指令

      EXPORT_ SYMBOL()
      EXPORT_SYMBOL_GPL()。
    
  • 导出的内核符号表:导出的内核接口,称为内核API。

  • 在声明函数后,紧跟上EXPORT_SYMBOL()。

三、设备模型

实现设备模型的最初动机:可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。

1. kobject

  • 设备模型的核心部分。
  • struct kobject 结构体表示,定义于头文件<linux/k,ρ1lij四t.b>中。
  • 通常是嵌入其他结构中的。

2. ktype

  • kobject 对象被关联到一种特殊的类型:ktype。
  • 由kobj_type 结构体表示,定义于头文件<linux/kobject.h>中。
  • 为了描述一族kobject 所具有的普遍特性。

3. kset

  • 在Linux 内核中,只有少数一些的ktype,却有多个kset。
  • 由kset 结构体表示,定义于头文件<linux/kobject.h>中:

4. kobject、ktype、kset关系

  • kobject,让那些包含它的结构具有了kobject 的特性。
  • ktype 定义了一些kobject 相关的默认特性。
  • kset 提供了两个功能:第一,其中嵌入的kobj创作为kobject 组的基类。第二, kset 将相关的kobject 集合在一起。

5. 管理和操作kobject

  • kobject 通过函数koject_init 进行初始化,该函数定义在文件<linux/kobject.h>中:void kobject_init(struct kobject kobj, struct kobj_type ktype);
  • 第一个参数就是需要初始化的kobject 对象;
  • 调用初始化函数前, kobject 必须清空;
  • 未被清空,调用memset() 即可:memset(kobj, 0, sizeof (*kobj ) );
  • 应该调用kobject_createO 创建koject。

6. 计数

  • kobject的主要功能:提供了一个统一的引用计数系统。

  • 初始化后,kobject的引用计数设置为1;引用计数不为零,该对象就会继续保留在内存中。

  • 引用计数跌到零时,对象可被撤销,相关内存也被释放。

  • koject 的引用计数是通过kref结构体实现,该结构体定义在头文件<linux/kref.h>中。

      - 增加引用计数称为获得对象的引用,减少引用计数称为释放对象的引用。
      - 当引用计数跌到零时,对象便可以被撤销,同时相关内存也都被释放。
    

四、sysfs

sysfs文件系统是个处于内存中的虚拟文件系统
  • 它为我们提供了 kobject 对象层次结构的视图。
  • 帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。

1. sysfs中添加和删除kobject

  • 函数都定义于文件 lib/kobject.c 中,声明于头文件<linux/kobject.b>中。

2. 向sysfs中添加文件

  • 默认属性:默认的文件集合是通过kobject和kset中的ktype字段提供的。因此所有具有相同类型的kobject在它们对应的sysfs目录下都拥有相同的默认文件集合。

  • 创建新属性:在sysfs 中创建一个符号连接

      int sysfscreatelink(struct kobject kobj, struct kobject target, char name);
    
  • 删除新属性:删除一个属性需通过函数sysfsremove file()完成

      void sysfsremovefile (struct kobject kobj, const struct attribute attr);
    
  • 由sysfs_ creat_ link()创建的符号连接可通过删除:

      void sysfsremovelink(struct kobject kobj , char name);
    

3. sysfs 约定

  • 保证每个文件只导出一个值。
  • 以一个清晰的层次组织数据。
  • 提供内核到用户空闹的服务。

4. 内核事件层

  • 实现了内核到用户的消息通知系统。
  • 内核事件由内核空间传递到用户空间需要经过netlink。
  • 用户空间实现一个系统后台服务用于监听套接字,处理任何读到的信息,并将事件传送到系统栈里。