https://zhuanlan.zhihu.com/p/483160418

一、模块指令

https://www.pianshen.com/article/2706300609/

modinfo -p mod名:查看mod的可用参数信息

参数传递

加载模块时传递参数

传递参数时如果参数名称写错了,会报错:unknown parameter 'var_out' ignored

二、模块化编程

1.编写模块

最简单的示例

必须用c语言编写
https://blog.csdn.net/nanfeibuyi/article/details/105034422

基本步骤:

  1. 引用相关的头文件
    #include <linux/init.h>   //module_init(),module_exit()
    #include <linux/module.h> //MODULE_LICENSE(), MODULE_AUTHOR()
  2. 需要编写一个初始化/加载函数--init()函数和一个退出/卸载函数--exit()函数。
    其中使用module_init(初始化函数)来指定初始化函数,使用module_exit(退出函数)来指定退出函数。
    模块加载时会调用初始化函数,模块卸载时会调用退出函数。

    3.添加模块相关描述信息

    MODULE_LICENSE("GPL"); 说明遵循GPL协议
    MODULE_AUTHOR("Genven_Liang"); 说明作者信息

简单示例:

#include <linux/init.h>   //__init, __exit
#include <linux/module.h> //module_init(), module_exit(),MODULE_LICENSE(),MODULE_AUTHOR(),MODULE_DESCRIPTION()

MODULE_LICENSE("GPL"); //声明协议
MODULE_AUTHOR("Genven_Liang"); //作者信息
MODULE_DESCRIPTION("test for linux driver."); //对本驱动程序的描述

//初始化函数 执行insmod时会调用该函数
static int __init hello_init(void)
{
    printk("hello_init!\n");
    return 0;
}

//退出函数  执行remod时会调用该函数
static void __exit hello_exit(void)
{
    printk("hello_exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);

模块语法

2.编译模块

https://zhuanlan.zhihu.com/p/409648724

编译方式

1)内部编译:将驱动程序源码放在内核源码目录中进行编译
2)外部编译:将驱动程序源码放在内核源码目录外进行编译
3)静态编译:编译进uImage中
4)动态编译 (.ko文件,动态加载驱模块)
外部编译+动态编译

编译模块命令`make -C M=`,https://blog.csdn.net/qq_40334837/article/details/89515751

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

这句是Makefile的规则:这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件。

M是内核根目录下的Makefile中使用的变量

内部编译(将驱动源码集成到内核并参加编译)

https://blog.csdn.net/Naisu_kun/article/details/126362277
编写好的驱动模块的Kconfig和Makefile,然后集成到driver根目录下的Kconfig与Makefile中。假如我的驱动模块目录为daiq,则:

1.向父目录中的Makefile添加:
 obj-y                           += daiq/ 
表示在编译过程中包含子目录daiq目录。
2.修改Kconfig文件,添加:
source "drivers/daiq/Kconfig"
表示在配置时引用子目录daiq中的配置文件Kconfig。

驱动编译错误整理

三、模块与驱动

https://blog.csdn.net/weixin_44818675/article/details/135386653

模块的诞生背景

linux内核整体结构非常庞大,其包含的组件也非常多。我们怎么把需要的部分都包含在内核中呢?

一种办法是把所有的需要的功能都编译到内核中。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,不得不重新编译内核,工作效率会非常的低,同时如果编译的模块不是很完善,很有可能会造成内核崩溃。

linux提供了另一种机制来解决这个问题,这种集中被称为模块,可以实现编译出的内核本身并不含有所有功能,而在这些功能需要被使用的时候,其对应的代码可以被动态的加载到内核中。

模块特点

1)模块本身并不被编译入内核,从而控制了内核的大小。
2)模块一旦被加载,他就和内核中的其他部分完全一样。

模块与驱动的关系

模块并不是驱动的必要形式:即:驱动不一定必须是模块,有些驱动是直接编译进内核的;同时模块也不全是驱动,例如我们写的一些很小的算法可以作为模块编译进内核,但它并不是驱动。就像烧饼不一定是圆的,圆的也不都是烧饼一样。


0 条评论

发表回复

您的电子邮箱地址不会被公开。