嵌入式 LINUX 驱动开发 day01 第一个内核模块程序 多文件编译为一个程序, 内核模块参数, 内核模块依赖

1.第一个内核模块程序  (  记得配置自己的交叉编译的工具,)

首先两个文件   vser.c   Makefile (记得大写的M)

vser.c

#include <linux/init.h>     //内核初始化头文件
#include <linux/module.h>   //内核模块文件
#include <linux/kernel.h>   //linux内核
/********** 自定义初始化函数 ***********/
static int __init vser_init(void)   /* __init 说明要将该函数放到 EIF 文件 __init 只读区 ,会加载后自动删除*/
{
    printk("我是初始化函数: %s\n",__func__);    //注意:内核中尽量不要用浮点数,所以printk不支持 %f 

    return 0;
}


/********** 自定义销毁函数 *************/
static void __exit vser_exit(void)
{
    printk("我是销毁函数: %s\n",__func__);
}

module_init(vser_init);//将vser_init函数地址加入到内核初始化链表
module_exit(vser_exit);//将vser_exit函数地址加入到内核卸载链表

MODULE_LICENSE( "GPL" );//开元许可协议:GPL
MODULE_AUTHOR("1111" );//作者信息
MODULE_DESCRIPTION(",你可以编写自己喜欢的模块");//模块描述信息
MODULE_ALIAS ( "2222" );  //模块别名

Makefile

#动态编译内核驱动生成.ko文件的Makeifle

#自己的模块代码名
obj-m = vser.o	#就会生成一个 vser.ko 文件  这是一个文件编译

#内核源代码路径
ifeq ($(ARCH),arm)
	KERNELDIR ?= /home/student/linux-5.4.31
else
	KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif

#当前模块路径
PWD ?= $(shell pwd)

#编译源码生成 .ko 文件 make all
all:
	${MAKE} -C ${KERNELDIR} M=${PWD} modules

#伪代码之清除垃圾
clean:
	rm Module.* modules.* *.mod *.ko

等下运用  下面的内核的指令就可以了。   (运行命令生成  .ko 文件)

统一放在  一个文件夹里面。


2. 内核的指令   ()

1. (编译生成 .ko 文件)

命令:  make   或者   make ARCH=arm     

make
make ARCH=arm

2.模块加载

命令 : sudo insmod  vser.ko    (vser  上面编译的 .ko 文件 )  (普通用户权限下)

sudo insmod  vser.ko

命令 : insmod vser.ko 

 insmod vser.ko 


3. 查看模块信息

命令 : modinfo vser.ko

modinfo vser.ko


4. 模块卸载

命令 : sudo rmmod vser   (普通用户)

sudo rmmod vser

  命令: rmmod  vser   (超级用户)

 rmmode  vser 

5.   查看 模块是否加载  

命令: lsmod     (一般最后加载的  在最前面 )

lsmod 


6. 查看 模块运行问题

命令: dmesg  

dmesg



3.内核多文件的编译成一个文件

1. bar .c

#include <linux/kernel.h>

void bar(void)
{
    printk("加载外部函数名字 %s\n",__func__);
}

2. foo.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

/**** extern 引入外部声明 ****/
extern void bar(void);

/**** 初始化函数 *****/
static int __init vser_init(void)
{
    printk("加载函数名:%s\n",__func__);
    bar();  //调用外部函数

    return 0;
}

/**** 注销函数 ***/
static void __exit vser_exit(void)
{
    printk("卸载函数名:%s\n",__func__);
}

/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);

/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL");  //开元许可协议

3.Makefile

#动态编译内核驱动生成.ko文件的Makeifle

#自己的模块代码名
obj-m = vser.o	#就会生成一个 vser.ko 文件
vser-objs = foo.o bar.o

#内核源代码路径
ifeq ($(ARCH),arm)
	KERNELDIR ?= /home/student/linux-5.4.31
else
	KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif

#当前模块路径
PWD ?= $(shell pwd)

#编译源码生成 .ko 文件 make all
all:
	${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
	rm Module.* modules.* *.mod *.ko


3. 内核模块参数

1. vser.c

#include <linux/init.h>     //内核初始化头文件
#include <linux/module.h>   //内核模块文件
#include <linux/kernel.h>   //linux内核
/********** 自定义初始化函数 ***********/


static int baudrate= 9600;
static int port[4] = {0,1,2,3};
static char *name = "vser" ;

module_param(baudrate,int,S_IRUGO);
module_param_array(port, int,NULL,S_IRUGO);
module_param(name,charp,S_IRUGO);







static int __init vser_init(void)   /* __init 说明要将该函数放到 EIF 文件 __init 只读区 ,会加载后自动删除*/
{
        int i = 0;
	printk("baudrate = d\n" , baudrate);
	printk("prot=");
	for(i =0; i<4;i++)
	{
	    printk ( "%d, " , port[i]);
	}
	printk ( "\n");
	printk( "name = %s\n" , name);

	
    printk("我是初始化函数: %s\n",__func__);    //注意:内核中尽量不要用浮点数,所以printk不支持 %f 

    return 0;
}


/********** 自定义销毁函数 *************/
static void __exit vser_exit(void)
{
    printk("我是销毁函数: %s\n",__func__);
}



/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);

/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL");  //开元许可协议

2.Makefile

#动态编译内核驱动生成.ko文件的Makeifle

#自己的模块代码名
obj-m = vser.o	#就会生成一个 vser.ko 文件

#内核源代码路径
ifeq ($(ARCH),arm)
	KERNELDIR ?= /home/student/linux-5.4.31
else
	KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif

#当前模块路径
PWD ?= $(shell pwd)

#编译源码生成 .ko 文件 make all
all:
	${MAKE} -C ${KERNELDIR} M=${PWD} modules

#伪代码之清除垃圾
clean:
	rm Module.* modules.* *.mod *.ko

参数默认值

可以用命令改变   (先 make  编译  形成  vser.ko  文件  再  模块加载)

查看他们的值



4. 内核模块 依赖 (不同与 多文件编译)

dep.c

#include <linux/kernel.h>
#include <linux/module.h>

static int expval =5;
static void expfunc(void)
{
	printk("依赖函数:expfunc\n");
}

EXPORT_SYMBOL(expval); //
EXPORT_SYMBOL_GPL(expfunc);

MODULE_LICENSE("GPL");  

vser.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

/**** extern 引入外部声明 ****/
extern void expfunc(void);
extern int expval; 


/**** 初始化函数 *****/
static int __init vser_init(void)
{
    printk("初始化函数:%s\n",__func__);
    printk("expval = %d\n",expval);
    expfunc();

    return 0;
}

/**** 注销函数 ***/
static void __exit vser_exit(void)
{
    printk("卸载函数名:%s\n",__func__);
}

/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);

/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL");  //开元许可协议

Makefile

#动态编译内核驱动生成.ko文件的Makeifle

#自己的模块代码名
obj-m = vser.o	#就会生成一个 vser.ko 文件
obj-m += dep.o

#内核源代码路径
ifeq ($(ARCH),arm)
	KERNELDIR ?= /home/student/linux-5.4.31
else
	KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif

#当前模块路径
PWD ?= $(shell pwd)

#编译源码生成 .ko 文件 make all
all:
	${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
	rm Module.* modules.* *.mod *.ko

运行步骤:  (上面的 步骤都差不多,, 只是有一个的加载命令不一样)

1. make   (形成  .ko 文件)

2. sudo rmmod  vser   (  移除模块  防止之前的 vser.ko  已经加载)

3. sudo  insmod vser.ko   (加载模块)

4. lsmod   (查看是否有 vser  模块)

5. dmesg  (查看 模块的加载  输出)

6. sudo rmmod  vser 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值