http://oss.org.cn/kernel-book/ldd3/index.html
《Linux 设备驱动 Edition 3》学习笔记
第二章
1.大多数小规模和中规模应用程序时从头到尾执行单个任务,而核心模块缺只是预先注册资金以便服务于将来的某个请求,然后它的初始化函数就立即结束。
2.核心模块运行在所谓的内核空间,而应用程序运行在用户空间中。
3.我们通常将运行模式称作内核空间和用户空间,这两个术语不仅说明两种模式具有不同的优先权等级,而且还说明每个模式都有自己的内存映射,就是自己的地址空间。
4.内核中的并发,即使最简单的内核模块,都需要在编写时铭记,同一时刻,可能会有许多事情正在发生。
5.应用程序在虚拟内存中布局,并具有一块很大的栈空间。内核具有非常小的栈,因此,声明大的自动变量并不是一个很好的主意。如果我们需要大的结构,则应该在调用时动态分配该结构。
6.在内核API中看到的具有两个下划线前缀“__"的函数名称,具有这种名称的函数通常是接口的底层组建,应该谨慎使用。
7.我们了解到insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量)的地址,这是实现模块化驱动程序所必须的。当模块被装入内核后,它所导出的任何符号都会变成内核符号表的一部分。
8.module_init的使用是强制性的,用于说明内核初始化函数所在的位置。模块可以注册许多不同类型的设施,包括不同类型的设备、文件系统、密码变换等。对每种设施,对应有具体的内核函数用来完成注册。传递到内核注册函数中的参数通常是指向用来描述新设施及设施名称的数据结构指针,而数据结构通常包含指向模块函数的指针,这样,模块体中的函数就会在恰当的时间被内核调用。
第三章
1. 对字符设备的访问是通过文件系统内的设备名称进行的。那些名称被称为特殊文件、设备文件,或者简单称为文件系统树的节点,它们通常位于/dev目录。字符设备驱动程序的设备文件可以通过ls -l命令输出的第一列中的“c”来识别。块设备也出现在/dev下,但它们由字符"b"标识。
2.次设备号由内核使用,用于正确确定设备文件所指的设备。依赖于驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可将次设备号作为设备本地数组的索引。不管哪种方式,除了知道次设备号用来指向驱动程序所实现的设备之外,内核基本不关心关于次设备号的任何其他信息。
3.在<linux/fs.h>中定义的struct file是设备驱动程序所使用重要数据结构,struct file是一个内核结构,它不会出现在用户程序中,所以它和用户空间程序中的FILE没有关联。file结构代表一个打开的文件(它并不仅仅限定于设备驱动程序,系统中每个打开的文件在内核空间都有一个对应的file结构)。它由内核在open时创建,并传递给在该文件上进行操作的所有函数,直到最后的close函数。在文件的所有实例都被关闭后,内核会释放这个数据结构。在内核源码中,指向struct file的指针通常被称作filp(文件指针)。
4.file->private_data(void *private_data)字段,open系统调用在调用驱动程序的open方法前将这个指针设置为NULL。驱动程序可以将这个字段用于任何目的。驱动程序可以用这个字段指向已经分配的数据,但是一定要在内核销毁file结构前在release方法中释放内存。private_data是跨系统调用时保存信息的非常有用的资源。
5.由于驱动程序从不自己填写file结构,而只是对别处创建的file结构进行访问,所以忽略file中的某些字段是安全的。
6.内核用indoe结构在内部表示文件,它和file结构不同,后者表示打开的文件描述符。对单个文件,可能会有许多表示打开的文件描述符的file结构,但是它们都指向单个inode结构。
7.open方法提供给驱动程序以初始化的能力,从而为以后的操作完成初始化做准备。大部分驱动程序中,open完成如下工作:
a 检查设备特定的错误
b 如果设备是首次打开,则对其进行初始化
c 如有必要,更新f_op指针
d 分配并填写filp->private_data里面的数据结构
8.read和write方法的buff参数是用户空间的指针。因此,内核代码不能直接引用其中的内容。原因有几个,例如其中一种是,用户空间的内存是分页的,而在系统被调用时,涉及到的内存可能根本就不在RAM中,对用户空间内存的直接引用将导致页错误。read方法的任务是从设备拷贝数据到用户空间,而write方法是从用户空间拷贝数据到设备上。
9.read和write方法返回值大于0,但是小于count,意味着只传递了部分数据,程序很可能再次试图写入、读取余下的数据。
10.readv和writev,这些”向量“型的函数具有一个结构数组,每个结构包含一个指向缓冲区的指针和一个长度值。readv调用可用于将指定数量的数据依次读入每个缓冲区。writev则是把每个缓冲区的内容收集起来,并将它们在一次写入操作中进行输出。如果驱动程序没有提供用于处理向量操作的方法,readv和writev会通过对read和write方法的多次调用来实现。
第四章
1./proc文件系统是一种特殊的、有软件创建的文件系统,内核使用它想外界导出信息。/proc下面的每个文件都绑定与一个内核函数,用户读取其中的文件时,该函数动态地生成文件的内存。例如,/proc/modules列出的是当前载入模块的列表。这些/proc文件不仅可以用于读取数据,也可以用于写入数据。不过,大多数时候,/proc入口项是只读文件。