第17章 设备与模块

关于设备驱动和设备管理的四种内核成分:

  • 设备类型:在所有 Unix 系统中为了统一普通设备的操作所采用的分类.
  • 模块: Linux 内核中用于按需加载和卸载目标码的机制.
  • 内核对象:内核数据结构中支持面向对象的简单操作,还支持维护对象之间的父子关系。
  • sysfs :表示系统中设备树的一个文件系统。

17.1 设备类型

设备三种类型:

  • 块设备

    • 通常缩写为 blkdev ,它是可寻址的,寻址以块为单位,块大小随设备不同而不同;
    • 支持重定位(seeking )操作,也就是对数据的随机访问 块设备的例子有硬盘、蓝光光牒,还有如 Flash 这样的存储设备;
    • 通过称为“块设备节点”的特殊文件来访问的.
  • 字符设备
    • 字符设备通常缩写为 cdev,它是不可寻址的,仅提供数据的流式访问;
    • 例子有键盘、鼠标、打印机,还有大部分伪设备。
    • 通过称为“字符设备节点”的特殊文件来访问的。
    • 与块设备不同,应用程序通过直接访问设备节点与字符设备交互。
  • 网络设备
    • 网络设备打破了 Unix 的“所有东西都是文件”的设计原则,它不 是通过设备节点来访问,而是通过套接字 API 这样的特殊接口来访问。 其他设备
    • “杂项设备”,是个简化的字符设备。杂项设备使驱动程序开发者能够很容易地表示一个简单设备。
    • “伪设备”的设备驱动是虚拟的,仅提供访问内核功能而 已。最常见的如内核随机数发生器(通过/dev/random和/dev/urandom 访问)、空设备(通过/dev/null 访问)、零设备(通过/dev/zero访问)等。

17.2 模块

Linux是单块内核的操作系统,但是Linux内核是模块化组成的,允许内核在运行时动态的向其中插入或从中删除代码。

17.2.1 Hello,World

基本模块:

  • hello_ init()函数是模块的入口点,通过module_init()例程注册到系统中。
  • hello_ exit()函数是模块的出口函数,通过module_exit()例程注册到系统,在返回前负责清理资源。
  • MODULE_LICENSE()宏用于指定模块的版权,如果载入非GPL模块到系统内存,则会在内核中设置被污染标识

17.2.2 构建模块

1、放在内核源代码树中

  • 把模块源码加入到内核源代码树中
  • 作为一个补丁或者是最终把你的代码合并到正式的内核代码树中.

2、放在内核代码外

  • 只用在自己的源代码树中建立Makefile,告诉make如何找到内核源代码文件和基础Makefile文件

17.2.3 安装模块

make module_install
通常需要以 root 权限运行

17.2.4 产生模块依赖性

产生内核依赖关系的信息:

depmod

只为新模块生成依赖信息:

depmod -A

17.2.5 载入模块

载入模块insmod 命令:

insmod module.ko

卸载模块rmmod 命令:

rmmod module

modprobe插入模块:

modprobe module [ module parameters ]

其中,参数 module 指定了需要载入的模块各称,后面的参数将在模块加载时传入内核。

modprobe卸载模块:

modprobe -r modules

17.2.6 管理配置选项

  • 配置选项第一行定义了该选项所代表的配置目标。注意 CONFIG_ 前缀并不需要写上。
  • 第二行声明选项类型为住istate,也就是说可以编译进内核(Y),也可作为模块编译(M),或者干脆不编译它(N)。如果编译选项代表的是一个系统功能,而不是一个模块,那么编译选项将用 bool 指令代替往istate,这说明它不允许被编译成模块。处于指令之后的引号内文字为该选项指定了名称。
  • 第三行指定了该选项的默认选择,这里默认操作是不编译它(则。也可以把默认选择指定为编译进内核飞凹,或者编译成一个模块(M)。对驱动程序而言,默认选择通常为不编译进内核(N)。
  • Help 指令的目的是为该选项提供帮助文档。各种配置工具都可以按要求显示这些帮助。因为这些帮助是面向编译内核的用户和开发者的,所以帮助内容简洁扼要。一般的用户通常不会编译内核,但如果他们想试试,往往也能理解配置帮助的意思。

17.2.7 模块参数

定义一个模块参数:

module_param(name,type,perm);

name:参数名,变量名
type:参数类型
perm:模块在sysfs文件系统下对应文件的权限,是八进制的格式,如0644表示所有者可以读写,组内可以读,其他人可以读

17.2.8 导出符号表

在内核中,导出内核函数需要使用特殊的指令:

EXPORT_ SYMBOL()和 EXPORTSYMBOLGPL()

17.3 设备模型

统一设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:

  • 代码重复最小化.
  • 提供诸如引用计数这样的统一机制。
  • 可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总结.
  • 可以将系统中的全部设备结构以树的形式完整、有效地展现出来一一包括所有的总统和内部连接。
  • 可以将设备和其对应的驱动联系起来,反之亦然。
  • 可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构.
  • 可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。

17.3.1 kobject

设备模型的核心部分就是 kobject,它自 struct kobject 结构体表示,定义于头文件<linux/kobject.b>中。

  • name指针指向此kobject的名称
  • parent指针指向kobject的父对象
  • sd指针指向sysfs_dirent结构体,该结构体在sysfs中表示的就是这个kobject
  • kref提供引用计数
  • ktype和kset结构体对kobject对象进行描述和分类

17.3.2 ktype

ktype 的存在是为了描述一族kobject 所具有的普遍特性.

  • release指针指向kobject引用计数减至零时要被调用的析构函数
  • sysfs_ ops变量指向sysfs_ops结构体,描述了sysfs文件读写时的特性
  • default_ attrs指向一个attribute结构体数组,该结构体定义了该kobject相关的默认属性

17.3.3 kset

kset 是 kobject 对象的集合体。把它看成是一个容器,可将所有相关的 kobject 对象,比如“全部的块设备”置于同一位置。

17.3.4 kobject、ktype和kset的相互关系

  • 最重要的是kobject,由 struct koject 表示。 kobject 为我们引入了诸如引用计数、父子关系和对象名称等基本对象道具,并且是以一个统一的方式提供这些功能。
  • kobject与一个特别的ktype对象关联,ktype定义了一些kobject相关的默认属性:析构行为、sysfs行为等。
  • kobject又归入了称作kset的集合。

17.3.5 管理和操作kobject

使用 kobjcet 的第一步需要先来声明和初始化。 kobject 通过函数ko均ect_init 进行初始化,该函数定义在文件 <linux/kobject.h>中 :

void kobjectinit(struct kobject •kobj, struct kobjtype •ktype);
  • 第一个参数就是需要初始化的 kobject 对象,在调用初始化函数前, kobject 必须清空。
  • 这个工作往往会在 kobject 所在的上层结构体初始化时完成。
  • 如果 kobject 未被清空,那么只需要调用 memset().

17.3.6 引用计数

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

1、递增和递减引用计数:

增加:kobject_get()
减少:kobject_put()

2、引用计数:kref:

获得对kref的引用:kref_get()
减少对kref的引用:kref_put()

17.4 sysfs

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

17.4.1 sysfs中添加和删除kobject

把kobject带入sysfs:

kobject_add()

先创建再导入:

kobject_create_and_add()

删除一个kobject对应文件目录:

kobject_del()

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

17.4.2 向sysfs中添加文件

1、 默认属性

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

2、创建新属性

添加新属性:

sysfs_create_file()

创建一个符号连接:

int sysfscreatelink(struct kobject kobj, struct kobject target, char name);

3、删除新属性

删除一个属性需通过函数sysfsremove file() 完成:

void sysfsremovefile (struct kobject kobj, const struct attribute attr);

由sysfs_ creat_ link()创建的符号删除:

void sysfsremovelink(struct kobject kobj , char name);

17.4.3 内核事件层

内核事件由内核空间传递到用户空间需要经过 netlink. netlink 一个用于传送网络信息的多点传送套接字。

在内核代码中向用户空间发送信号使用函数 kobject uevent():

int kobject_uevent(struct kobject *kobj,enum kobject_ action action);

第一个参数指定发送该信号的 koject 对象。实际的内核事件将包含该 koject 映射到 sysfs路径。
第二个参数指定了描述该信号的“动作”或“动词”。

20135220谈愈敏Linux Book_17的更多相关文章

  1. 20135220谈愈敏Linux Book_4

    进程调度 进程:程序的运行态表现形式 进程调度程序:确保进程能有效工作的一个内核子系统,决定将哪个进程投入运行.何时运行以及运行多长时间,在可运行态进程之间分配有限的处理器时间资源. 最大限度的利用处 ...

  2. 20135220谈愈敏Linux Book_3

    第3章 进程管理 进程是Unix操作系统抽象概念中最基本的一种,进程管理是操作系统的心脏所在. 3.1 进程 进程:处于执行期的程序以及相关的资源的总称. 线程:在进程中活动的对象,拥有独立的程序计数 ...

  3. 20135220谈愈敏Linux Book_18

    第18章 调试 调试内核艰难且风险高,关键在于对内核的深刻理解. 18.1 准备开始 需要的是: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 内核中的bug不是很清晰,调试成功的关 ...

  4. 20135220谈愈敏Linux Book_5

    第五章 系统调用 内核提供了用户进程与内核进行交互的一组接口. 应用程序发出请求->内核负责满足 目的:保证系统稳定可靠 5.1 与内核通信 系统调用在用户空间进程和硬件设备之间添加了一个中间层 ...

  5. 20135220谈愈敏Linux Book_1&2

    第一章 Linux内核简介 从unix的历史视角来认识Linux内核与Linux操作系统的前世今生. Unix历史 贝尔实验室设计的一个文件系统原型逐渐演化而成Unix,而后Unix操作系统用C语言重 ...

  6. 20135220谈愈敏Blog3_构造一个简单的Linux系统MenuOS

    构造一个简单的Linux系统MenuOS 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1 ...

  7. 20135220谈愈敏Blog8_进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-100002 ...

  8. 20135220谈愈敏Blog7_可执行程序的装载

    可执行程序的装载 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. ...

  9. 20135220谈愈敏Blog6_进程的描述和创建

    进程的描述和创建 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 进程 ...

随机推荐

  1. 远离腰痛的好方法——如何锻炼腰背部肌肉?

    在我们的骨科门诊中最常见到的就是腰痛患者:引起腰痛的原因很多,也比较复杂,所以就有俗语"病人腰痛.医生头痛"一说.其实,相当大部分的腰痛症状都是跟腰背部后方的肌肉筋膜劳损或者无菌性 ...

  2. mysql 命令行

    drop database mustang; create database mustang; show databases; use database mustang; show tables; s ...

  3. android之旋转的刻度盘

    这是在学习android的Canvas绘图技巧时做的一个实例.主要用的核心方法就是canvas.save,canvas.rotate, canvas.translate以及canvas.restore ...

  4. mmap 与 read/write

    mmap与read/write两条路线对文件的访问比较 我们知道无论是通过mmap或read/write访问文件在内核中都必须经过缓存, 当需要从文件读写内容时,都经过内存拷贝的方式与内核中的缓存进行 ...

  5. PHP模拟发送POST请求之二、用PHP和JS处理URL信息

    明白了HTTP请求的头信息后,我们还需要对请求地址有所了解.再者,HTTP GET请求是靠URL实现的,所以了解URL的构造,处理URL的重要性不言而喻. 在PHP中我们用parse_url()函数来 ...

  6. 烂泥:CentOS安装及配置TFTP服务器

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 为什么要学习有关TFTP服务器的安装及配置呢?主要是为了后续学习有关linux系统的无人值守安装做准备. TFTP简单文件传输协议,使用UDP的69端口 ...

  7. 通过反射获取SSM的controller层的注解以及注解中的value值

    package com.reflection.test; import java.lang.annotation.Annotation; import java.lang.reflect.Invoca ...

  8. SCAU巡逻的士兵

    1142 巡逻的士兵 Description 有N个士兵站成一队列, 现在需要选择几个士兵派去侦察. 为了选择合适的士兵, 多次进行如下操作: 如果队列超过三个士兵, 那么去除掉所有站立位置为奇数的士 ...

  9. linux进程间通信-XSI IPC

    一 什么是XSI IPC     有三种 IPC我们称作XSI IPC,即消息队列.信号量以及共享存储器(共享内存),它们之间有很多相似之处. 二 标识符和键     每个内核中的 IPC结构(消息队 ...

  10. Ubuntu 14.04 单机安装 CEPH

    0.如果先前安装过ceph,则先卸载 sudo stop ceph-all //停止所有CEPH进程 ceph-deploy uninstall [{ceph-node}] //卸载所有ceph程序 ...