模块作为一种抽象数据类型,它具有一个可以通过静态内核中断的接口。最小的模块结构必须包括两个函数:init_module()和cleanup_module(),它们在系统加载模块和卸载模块时被调用。也可以编写一个只包括这两个函数的模块,这样该模块中唯一会被调用的函数就是模块被加载时所调用的函数init_module()和模块被卸载时所调用的函数cleanup_module()。并且用函数init_module()来启动模块加载期间的操作,用函数cleanup_module()来停止这些操作。
由于模块可以实现相当复杂的功能,故可以在模块中加入很多新函数以实现所期望的功能。不过加入模块的每个新函数都必须在该模块加载到内核中时进行注册。若该模块是静态加载的,则该模块的所有函数都是在内核启动时进行注册;若该模块是动态加载的,则这些新函数必须在加载这个模块时动态注册。当然,如果该模块被动态卸载了,则该模块的函数都必须从系统中注销。通过这种方式,当这个模块不在系统中时,就不能调用该模块的函数。其中注册工作通常是在函数init_module()中完成的,而注销工作则是在函数cleanup_module()中完成。
#include // 说明是个内核功能
#include // 声明是一个模块
… … // 其它header信息
int init_module( )
{
… … // 加载时,初始化模块的编码
}
… …
… … // 期望该模块所能实现的一些功能函数,如open()、
release()、write()、 read()、ioctl()等函数
… …
void cleanup_module( )
{
… … // 卸载时,注销模块的编码
}
在内核是用一个file结构来识别模块,而且内核使用file_operations结构来访问模块程序中的函数。file_operations结构是一个定义在中的函数指针表。管理模块的文件操作,通常也称为“方法”,它们都为struct file_operations提供函数指针。在struct file_operations中的操作一般按如下顺序出现,除非特别说明,一般它们返回0值时表示访问成功;发生错误时会返回一个负的错误值(目前共有13个操作):
int (*lseek) ()、 int (*read)()、int (*write) ()
int (*readdir)()、int (*select)()、 int (*ioctl)()
int (*mmap)()、int (*open)()、void (*release)()
int (*fsync)()、int (*fasync)()
int (*check_media_change)()
int (*revalidate)()
具体下载目录在 /2012年资料/2月/26日/Linux模块编程实验 PPT/