您现在的位置: 万盛学电脑网 >> 操作系统 >> Linux教程 >> 正文

Linux--Linux内核模块编程之字符设备文件在线阅读

作者:佚名    责任编辑:admin    更新时间:2022-06-22

 字符设备文件
  因此现在我们是大胆的内核程序员而且我们知道如何写什么也不做的内核模块。我们为自己而自豪并且可以高高的仰起我们的头。但是不知何故我们感到遗失了什么。令人紧张的模块并不是很有趣的。
  内核模块有两种主要的途径和进程对话。一种是通过设备文件 (像 /dev 目录中的文件), 另一种是使用 proc 文件系统。因为写内核中的某些东西的一个主要的原因是去支持某种硬件,所以我们从设备文件开始。
  设备文件的原始目的是允许进程和内核中的设备驱动程序通信以通过它们和物理设备通信 (调制解调器, 终端, 等等)。 这个办法的实现是像下面这样的。
  每个设备驱动程序负责某种硬件,它被分配一个主设备号。驱动程序的列表和它们的主设备号可以在 /proc/devices找到。每一个物理设备由设备驱动程序控制且被分配一个次设备号。 /dev 目录被假设包含每一个这样的设备的被称之为设备文件的特殊文件,无论它是否被真正的安装在系统上。
  例如,如果你 ls -l /dev/hd[ab]*,你将看到所有的可能被连接到系统上的IDE硬盘的分区。注意它们都使用相同的主设备号,3。但是次设备号彼此都不相同。
否认申明: 这是假设你正字使用 PC 架构的系统。我不知道基于其他架构的Linux设备的情况。.
  当系统被安装,所有的那些设备文件被 mknod 命令创建。从技术上说没有必须将它们放在 /dev目录的原因,这只是一个有用的惯例。像练习所示的那样,当为了测试的目的而创建一个设备文件,将它放在你编译内核模块的那个目录也许更有意义。
  设备分为两种:字符设备和块设备。不同之处在于块设备对于请求有缓冲区,因此它们可以选择以什么顺序进行响应。对于存储设备而言这一点是很重要的,因为在读写连续的扇区时比远远的分离的扇区更快。另一个不同就是块设备只能以块为单位接受输入和返回输出(块的大小根据设备的不同而不同),而字符设备只能使用它们可能使用的或多或少的字节大小。大多数设备是字符设备,因为它们不需要这种缓冲而且不以固定块大小进行操作。你可以用ls -l区分一个设备文件是块设备还是字符设备.如果开头是“b”,那么它就是块设备;如果是“c”,那么就是字符设备。
  这个模块分为两部分:登记设备模块部分和设备驱动部分。 init_module 调用 module_register_chrdev 而将设备驱动程序加入内核的字符设备驱动程序表。它也返回该设备将使用的主设备号。 cleanup_module 注销该设备。
  这(登记什么和注销它)是那两种功能的常规功能。内核中的东西不想普通进程那样主动运行自己,而是由进程通过系统调用,或者由硬件通过中断,或者由内核的其他部分(简单的讲,由特殊的函数调用)进行调用。结果,当你向内核中加入代码,你被假设将之登记为某种事件句柄,而当你移除它时,你被假设出注销它。
  严格意义上讲,设备驱动程序由四个device_函数组成,当某人试图用我们的主设备号的设备文件做什么事时它被调用。内核是通过 file_operations结构知道要调用它们的,Fops, 在设备被登记时被给出,它包含那四个函数的指针。
  另一点我们在这必须记住的是我们不能允许内核模块在任何根感觉需要的时候被rmmod。原因是如果设备文件正被一个进程打开然后我们移除那个内核模块,这将使用那个文件,而这又将导致对那个适当的读写函数所在的内存区域的调用。如果幸运的话,没有其他的代码被加载到那儿,我们得到一个难看的错误消息。如果不幸运的话,另一个内核模块被加载到同一区域,这就意味着跳到内核中的另一个函数的中间,结果是不可预见的,但肯定不是什么好事。
  通常,当你不允许什么事情发生,你会从被假设做这件事的函数返回一个用负数表示的错误代码。使用cleanup_module 是不可能的,因为它不返回任何值。一旦cleanup_module 被调用,模块即死亡了。然而,这儿有一个被称为引用计数器(在/proc/modules中的相应行的最后一个数字)的计数器计算有多少其他的内核模块正在使用该模块。如果该数字非零 rmmod 调用将失败。模块的引用计数器在变量mod_use_count_中. 因为有处理这个变量的宏定义 (MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT),我们最好使用它们而不直接使用 mod_use_count_ ,这样,如果将来实现方法改变了我们会更安全。