网络设备在 Linux 里做专门的处理。 Linux 的网络系统主要是基于 BSD 的 socket 机制。网络设备驱动为网络操作提供接口,管理网络数据的接送和收发。为了屏蔽网络环境中物理网络设备的多样性, Linux 对所有的物理设备进行抽象并定义了一个统一的概念,称之为接口( interface )。所有对网络硬件的访问都是通过接口进行的,接口对上层协议提供一致化的操作集合来处理基本数据的发送和接收,对下层屏蔽硬件差异。它与字符设备及块设备不同之处其一就是网络接口不存在于 Linux 的设备文件系统 /dev/ 中。
和前一篇的介绍一样,看完外表,我们再看内涵,就是 Linux 驱动的工作流程。大概有四个部分:使用 insmod 加载,模块的初始化,进行设备操作,使用 rmmod 卸载。
Linux 驱动有两种存在形式,一种是直接编译进内核,就是我们在配置内核的时候,在相应选项上选 Y ,另外一种就是编译成模块,按需加载和卸载。通常我们使用 insmod 命令完成模块的加载,在加载时还可以指定模块参数。另外一个常用的加载工具是 modprobe ,它与 insmod 的不同在于它会检查模块之间的依赖关系,将该模块依赖的模块也加载到内核。
每个驱动都有自己的初始化函数,完成一些新功能的注册,这个初始化函数只是在初始化的时候被使用。在 Linux 系统里,设备以文件的形式存在,应用程序可以通过 open 、 read 等函数操作设备,通过设备文件实现对设备的访问。设备不再使用时,我们使用 rmmod 命令来卸载它,卸载的过程会调用到驱动的推出函数,每个驱动都必须有一个退出函数,没有的话,内核就不会允许去卸载它。
在对 Linux 驱动的外表和内涵都有了一个初步的认识之后,我们来看看作为一个驱动开发者,我们需要注意哪些问题。
首先,对模块机制的了解是开发 Linux 驱动的基础,因为我们编写驱动的过程也就是在编写一个内核模块的过程。早期版本的内核是整体式的,也就是说所有的部分都静态地连接成一个很大的执行文件。但是现在的内核采用的是新的机制,即模块机制:许多功能包含在模块内,当你需要时可以使用 insmod 去拥抱它,将它动态地载入到内核里,当你不需要时,则可以使用 rmmod 将它一脚踢开。这就使得 kernel 的内核很小,而且在运行的时候可以不用 reboot 就能够载入和替代模块。