课本第17、19和20章内容学习
关于设备驱动和设备管理,Linux主要有四种内核成分
设备类型:在所有Unix系统中为了统一普通设备的操作所采用的分类。
模块:Linux内核中用于按需加载和卸载目标码的机制。
内核对象:内核数据结构中支持面向对象的简单操作,还支持维护对象之间的父子关系。
sysfs: 表示系统中设备树的一个文件系统。
设备类型
在Linux以及所有Unix系统中,设备被分为以下三种类型:
块设备:通常缩写为blkdev,它是可寻址的,寻址以块为单位,块大小随设备不同而不同;块设备通常支持重定位操作,也就是对数据的随机访问。
字符设备:通常缩写为cdev,它是不可寻址的,仅提供数据的流式访问,就是一个个字符,或者一个个字节。
网络设备:最常见的类型有时也以以太网设备来称呼,它提供了对网络的访问,这是通过一个物理适配器和一种特定的协议进行的。
模块
尽管Linux是单块内核的操作系统—整个系统运行于一个单独的保护域中,但是Linux内核是由模块组成的。Linux允许内核在运行时动态地向其中插入或从中删除代码。
支持模块的好处是:基本内核镜像可以尽可能的小,因为可选的功能和驱动程序可以利用模块形式提供,模块允许我们方便地删除和载入内核,也方面了调试工作。
内核中增加了一个引人注目的新特性--统一设备模型(device model)。
设备模型
统一设备模型的最初动机是为了实现智能的电源管理,linux 内核为了实现智能电源管理,需要建立表示系统中所有设备拓扑关系的树结构,这样在关闭电源时,可以从树的节点开始关闭。
实现了统一设备模型之后,还给内核带来了如下的好处:
-
代码重复最小化(统一处理的东西多了)
-
提供诸如引用计数这样的统一机制
-
可以列举系统中所有设备,观察它们的状态,并查看它们连接的总线
-
可以将系统中的全部设备以树的形式完整,有效的展示出来--包括所有总线和内部连接
-
可以将设备和其对应的驱动联系起来,反之亦然
-
可以将设备按照类型加以归类,无需理解物理设备的拓扑结构
-
可以沿设备树的叶子向其根的反向依次遍历,以保证能以正确的顺序关闭设备电源
统一设备模型的核心部分就是 kobject,通过下面对kobject结构体的介绍,可以大致了解它是如何使得各个物理设备能够以树结构的形式组织起来的。
cdev中嵌入了kobject之后,就可以通过 cdev->kboj.parent 建立cdev之间的层次关系,通过 cdev->kobj.entry 获取关联的所有cdev设备等。
总之,嵌入了kobject之后,cdev设备之间就有了树结构关系,cdev设备和其他设备之间也有可层次关系。
ktype是为了描述一族的kobject所具有的普遍属性,也就是将这一族的kobject的属性统一定义一下,避免每个kobject分别定义。
kset是kobject对象的集合体,可以所有相关的kobject置于一个kset之中,比如所有“块设备”可以放在一个表示块设备的kset中。
kobject,ktype和kset之间的关系
这3个概念中,kobject是最基本的。kset和ktype是为了将kobject进行分类,以便将共通的处理集中处理,从而减少代码量,也增加维护性。
sysfs
sysfs是一个处于内存中的虚拟文件系统,它提供了kobject对象层次结构的视图。
可以用下面这个命令来查看 /sys 的结构
tree /sys # 显示所有目录和文件
或者
tree -L 1 /sys # 只显示一层目录
可移植性
牢记下面的规则:
1.ANSI C标准规定,一个char的长度一定是1个字节
2.尽管没有规定int类型的长度是32bit,但是linux当前所有支持的体系结构中,它都是32位的
3.short类型也类似,在当前所有支持的体系结构中,虽然没有明确规定,但都是16bit的
4.绝对不应该假定指针和long的长度,在Linux当前支持的体系结构中,他们可以在32bit和64bit间变换
5.由于不同的体系结构的long长度不同,不应该假设sizeof(int) = sizeof(long )
6.类似的,不要假设指针和int长度相等
不透明类型隐藏着他的内部格式或结构,开发者利用typedef声明一个类型,把它叫做不透明类型。
处理不透明类型是的原则:
1.不要假设类型的长度。这些类型在某些系统中可能是32bit,而在其他系统中又可能是64bit,并且,内核开发者可以任意修改这些类型的大小
2.不要将该类型转化回对应的C标准类型使用
3.编程时要保证在该类型实际存储空间和格式发生变化时代码不受影响
char型的符号问题
大部分体系结构上,默认char是带符号的,它可以从-128到127之间取值。但是也有例外,比如ARM结构,char就是不带符号的,他的取值范围是0-255.
因此,如果在自己的代码中使用了char型,要保证带符号和不带符号的情况下代码都没问题。如果能明确使用的哪一种,就直接声明它。
数据对齐
1.对齐是跟数据块在内存中的位置相关的话题,如果一个变量的内存地址正好是他的长度的整数倍,他就称作是自然对齐。
2.编译器会同过让所有的数据自然对齐来避免引发对齐问题。实际上,内核开发者在对齐上不用话费太多心思。
3.但了解一些也终归是好的嘛。
举个例子,将一个指向char型的指针当作指向unsignedlong型的指针用,会引起问题,因为此时会试图从一个并不能被4或8整除的内存地址上载入32或64位的unsignedlong型数据。
非标准C数据类型按照下面原则对齐:
1.对于数组,只要按照基本数据类型进行对齐就可以,随后的所有元素自然能够对齐
2.对于联合体,只要它包含的长度的最大数据类型能够对齐就可以
3.对于结构体,只要结构体每一个元素能够正确对齐就可以
字节顺序
如果最高有效位所在的字节放在低字节位置上,其他字节依次放在高字节位置上,那么该字节顺序称作高位优先(big-endian)。如果最低有效位所在的字节放在高字节位置上,其他字节依次存放在低字节位置上,那么就称做低位优先(little-endian)。
补丁、开发和社区
加入社区
如果想为linux贡献代码,那么加入linux社区是必须的, 加入了社区, 不仅可以及时内核的最新消息,而且可以及时和社区内有经验的内核开发者交流经验。
同时也是提交代码和讨论代码的地方,了解社区的规则, 融入社区环境之中, 才能更好的学习内核, 体会内核开发的乐趣和成就感。
内核社区说白了就是内核邮件列表(LKML linux kernel mail list)
订阅邮件列表的网址: http://vger.kernel.org/vger-lists.html 这里面有linux相关的各种邮件列表
关于内核的邮件列表是: http://vger.kernel.org/vger-lists.html#linux-kernel
除了邮件列表之外, 还有2个本书作者推荐的网站也适合linux内核新手去关注:
http://kernelnewbies.org/ 有很多适合内核开发入门的资源
http://www.lwn.net/ linux 新闻周刊
编码风格
社区给我们提供了学习和贡献内核的地方, 但是为了避免不必要的麻烦(被别人指责或者无人理睬), 首先得好好了解一些内核代码的编码风格。
linux的编码风格都记录在 Documentation/CodingStyle 内核开发前要好好研读一下。
提交补丁
准备工作都完成之后, 就可以开始内核开发之旅了
只要坚持不断的学习和尝试,总有一天会为了内核贡献自己的代码,这时候,就需要了解如何提交代码,也就是内核补丁。
如果是发现了BUG或者有改善, 可以将BUG的描述或者改善代码发送给对应的维护者.(内核各个子系统的维护者信息在内核代码根目录下的 MAINTAINER 文件中)
问题与解答
kset和ktype都是为了将kobject进行分类,为什么会有2中分类呢?
从整个内核的代码来看,其实kset的数量是多于ktype的数量的,同一种ktype的kobject可以位于不同的kset中。
ktype侧重于描述,kset侧重于管理。