模块:指令集合,独立命名,能独立完成某一功能,提供接口。
1 应用程序和底层驱动的区别
应用程序驱动
加载方式主动加载被动加载
运行空间userkernel
权限低高
作用范围影响局部影响全局
函数来源库函数/系统接口内核提供的函数
2 如何写一个模块
#include
/* These are either module local, or the kernel's dummy ones. */
加载模块调用的初始化函数
extern int init_module(void); 卸载模块
extern void cleanup_module(void); 通过makefile编译,扩展名为.ko文件加载模块使用命令
sudo insmod xxx.ko
需要使用root权限加载
查看模块打印信息
dmesg | tail
查看模块信息描述
modinfo xxx.ko
查看当前系统中所有已加载的驱动模块
lsmod
卸载模块命令
sudo rmmod xxx
通常情况下使用内核提供的宏来加载和卸载模块加载
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
卸载
#define module_exit(exitfn)
static inline exitcall_t __exittest(void)
{ return exitfn; }
void cleanup_module(void)
__attribute__((alias(#exitfn)));
为模块增加信息
MODULE_AUTHOR("shixh");
MODULE_DESCRIPTION("test moduel");
MODULE_ALIAS("17021");
MODULE_LICENSE("GPL"); ***** GPL通用许可授权,一般
情况下载linux下的驱动都符合这个授权标准。
MODULE_VERSION("1.0.0.0");
obj-m := hello.o 指的是目标文件,通过hello.o编出hello.ko hello-objs = hello_init.o hello_exit.o 指的是编出hello.o需要
哪些文件
3 模块传参
通过宏来传递参数
#define module_param(name, type, perm)
\
module_param_named(name, name, type, perm)
* module_param - typesafe helper for a module/cmdline parameter
* @value: the variable to alter, and exposed parameter name. 变量名
* @type: the type of the parameter 变量类型
* @perm: visibility in sysfs. 可见性(注意8进制表示)
传参类型
* Standard types are:
* byte, short, ushort, int, uint, long, ulong
* charp: a character pointer
* bool: a bool, values 0/1, y/n, Y/N.
* invbool: the above, only sense-reversed (N = true).
例如
module_param(g_iTest, int, 0)
value : g_iTest, type : int, perm : 0 (0表示在文件系统中不可见, 0644文件系统可见,root权限可修改)
传参:
sudo insmod hello.ko g_iTest=18 (注意等号两边不能有空
格)
参数查看路径
/sys/moudles/xxxxxx/parameters xxx指的是模块名
当perm为0644时root权限可修改参数,通常情况下不建议
修改
根据参数名生成一个普通文件,当模块卸载时,模块对应的文件夹自动删除
注意:使用module_param传递字符串时注意是否越界,有点像
gets
传字符串时使用
#define module_param_string(name, string, len, perm)
fgets
/**
* module_param_string - a char array parameter
* @name: the name of the parameter 变量名
* @string: the string variable 变量名
* @len: the maximum length of the string, incl. terminator buf最大长度
* @perm: visibility in sysfs. 可见性
*
* This actually copies the string when it's set (unlike
type charp).
* @len is usually just sizeof(string).
*/
传递数组
#define module_param_array(name, type, nump, perm) /**
* module_param_array - a parameter which is an array of some type
* @name: the name of the array variable 数组名
* @type: the type, as per module_param() 类型
* @nump: optional pointer filled in with the number written 传递给数组的元素个数,需要传递一个指针
* @perm: visibility in sysfs 可见性
*
* Input and output are as comma-separated values. Commas inside values
* don't work properly (eg. an array of charp).
*
* ARRAY_SIZE(@name) is used to determine the number of elements in the
* array, so the definition must be visible.
*/
例如 sudo insmod hello.ko g_iArr=1,2,3 注意:数组方式传参时以逗号分隔
4 导出符号
导出符号所使用的宏 : EXPORT_SYMBOL_GPL /
EXPORT_SYMBOL
查看全局符号表命令 sudo cat /proc/kallsyms
例如在hello模块导出变量或函数,在world模块中使用导出的函数或变量
1 在hello模块使用 EXPORT_SYMBOL_GPL 导出,编译时会在Module.symvers文件中保存导出符号的地址
2 把Module.symvers文件拷贝到hehe模块文件夹中,并编译,注意:在world模块中使用导出的函数或变量要使用extern声明
注意Makefile中要使用不同的目标名,因为在模块加载时不允许出现同名模块