在Linux内核中,模块化的设计是非常普遍的。Linux内核的一大优点就是支持模块的动态加载与移除。这让驱动的开发和调试变得相当容易,并且在实际的使用中也是非常方便的。
在Linux内核中,模块指的是一些具有特定功能的代码集。在内核开发中通常将一个模块放在同一个.c文件中。模块通常有两个函数:
int xxx_init(void);
void xxx_exit(void);
module_init(xxx_init);
module_exit(xxx_init);
init函数通常是做一些该模块其它部分运行所必须的初始化工作。该函数的原型如上,它会在模块被加载到内核时调用。该函数需要使用宏控module_init()声明,目的是告诉编译器该函数的链接规则。exit函数与init函数对应,是在模块移除时被调用,主要是清除一些该模块使用的资源,例如释放在使用该模块时申请到的动态内存等等。
框架则是内核开发者提供给驱动开发与应用开发的上下接口。通过这些接口,驱动开发者无需完全知道应用开发者如何使用设备,只需要按照框架提供的接口实现即可。而应用开发者也无需完全明白设备底层如何操作,只需要通过框架提供的接口进行操作(准确来说是系统将框架的接口封装成系统API提供给应用程序开发者使用)。
Linux内核是通过许多个模块构建出Linux的设备驱动框架,一方面内核可以更好的管理设备,另一方面,对于驱动开发者来说也少了一些麻烦。那如何阅读驱动框架源码,并且使用其做具体的驱动开发?目前我阅读框架的方式是:从init函数入手,首先需要明白当前模块运行的先决条件;接下来分析其余函数的作用,在框架部分内核只提供了接口,并未做具体实现,因此在读这些框架时可以找一些具体的底层驱动辅助理解这些接口的设计。例如在阅读输入类设备框架input.c文件时,可以找具体的按键驱动辅助理解。