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

news2025/1/21 12:10:22

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 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/151820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础算法每日5道详解(6)

112. Path Sum 路径总和 Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum. A leaf is a node with no children. Example 1: Input: ro…

html+css实现一个响应式管理平台架构模板

文本将会带你使用htmlcss实现一个响应式的管理平台架构模板&#xff0c;目前来说市面上的管理平台架构模板大同小异&#xff0c;文本的知识点都会符合场景所需。 目录 1、管理平台的架构内容 2、顶部的布局 3、下半部分布局 4、左侧菜单区域实现 5、右侧主体区域实现 …

前端重新部署如何通知用户刷新网页?

我把我掘金的文章同步一份给CSDN 1.目标场景 有时候上完线&#xff0c;用户还停留在老的页面&#xff0c;用户不知道网页重新部署了&#xff0c;跳转页面的时候有时候js连接hash变了导致报错跳不过去&#xff0c;并且用户体验不到新功能。 2.思考解决方案 如何去解决这个问…

顶象助力绿球金科打造App低碳出行场景

“低碳出行”、“碳中和”、“碳惠普”正在成为近几年的科技热词之一。 自2020年9月&#xff0c;中国向世界许下“力争2030年前实现碳达峰&#xff0c;2060年前实现碳中和”的承诺以来&#xff0c;一场围绕绿色节能、低碳减排的变革正在席卷各行各业。 “碳中和”已经成为时代…

如何让SCI期刊审稿人,理解你的文章? - 易智编译EaseEditing

首先需要对论文进行全文润色 对于发表论文来说&#xff0c;进行润色是必须的&#xff0c;正因为SCI论文翻译要求高难度大&#xff0c;无论笔译还是口译都一定要有过硬的基本功&#xff0c;知识面要足够宽广&#xff0c;专业综合能力要求高。 所以当一篇论文的整体结构不到位&…

凯恩帝机床联网

一、设备信息确认 1、确认型号 数控面板拍照确认&#xff1a; 此系统为&#xff1a;K1TCi 注&#xff1a;凡是系统中带i的&#xff0c;基本上都含网口。 2、确认通讯接口 网口常见位置&#xff0c;XS92&#xff08;丝印标号&#xff09;&#xff0c;可通过这个确认&#x…

PnetLab模拟器安装锐捷镜像

安装准备&#xff1a; 1.安装完成pnetlab&#xff0c;这里不过多叙述&#xff1b; 2.在锐捷的网站下载好模拟器镜像&#xff08;目前只支持Switch和Router&#xff09;&#xff0c;下载地址&#xff1a;https://www.ruijie.com.cn/fw/wd/88899/ 官网下载后的内容包括下面几个…

Linux umount报错:device is busy

执行nfs卸载命令umount /mnt&#xff0c;报错target is busy. 或device is busy可以按以下步骤检查&#xff1a;退出要卸载挂载的目录&#xff0c;再执行卸载挂载cd ../umount /mnt找出占用目录的端口&#xff0c;kill端口fuser -m /mnt/kill -9 端口umount /mnt停止nfs服务&am…

计算机基础——操作系统

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.操作系统 1.操作系统简介 2.操作系统的主要功能 &#xff08;1&#xff…

【Kotlin】字符串操作 ② ( 字符串替换函数 replace | 字符串比较操作符 == 和 === | 字符串遍历 forEach )

文章目录一、字符串替换函数 replace二、字符串比较操作符 和 三、字符串遍历 forEach一、字符串替换函数 replace 字符串替换函数 replace 函数原型如下 : /*** 返回一个新字符串&#xff0c;通过替换此字符序列中匹配给定正则表达式的每个子字符串获得* 用给定的[替换]。**…

一个芯片工程师的ADC学习笔记 (二)

众所周知&#xff0c;ADC主要用于对模拟信号进行数字采集&#xff0c;以进行数据处理。我们周围的信号一般都是不断变化的模拟量&#xff0c;如光、温度、速度、压力、声音等。然而&#xff0c;我们大多数人都使用数字设备。如果我们想方便地使用和处理信息&#xff0c;就需要将…

【机器学习】关联规则挖掘算法 + 三大案例实战 + Apriori算法 + Python代码实现

文章目录一、关联规则概述1.1 关联规则引入1.2 关联规则相关概念介绍1.2.1 样本、事务、项集、规则1.2.2 支持度、置信度1.2.3 提升度1.2.4 所有指标的公式二、Python实战关联规则2.1 使用 mlxtend 工具包得出频繁项集与规则2.1.1 安装 mlxtend 工具包2.1.2 引入相关库2.1.3 自…

MP3解码算法原理解析

一&#xff1a;MP3编解码整体结构介绍 看懵逼了是吧。这里面有很多概念需要一一讲解。 比特流&#xff1a;比特流是一种内容分发协议。它采用高效的软件分发系统和点对点技术共享大体积文件&#xff08;如一部电影或电视节目&#xff09;&#xff0c;并使每个用户像网络重新分配…

记录--微信调用jssdk--Invalid Signature, updateAppMessageShareData: denied等问题

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 最近在做安卓内嵌入H5活动页拉新活动&#xff0c;遇到的棘手问题记录下&#xff0c; 一是为了日后遇到同样问题好回顾&#xff0c;二是希望能帮到有同样问题的兄弟。 废话不多说&#xff0c;先从最棘手…

【高阶数据结构】封装Map和Set

&#x1f308;欢迎来到数据结构专栏~~封装Map和Set (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一…

蓝桥杯Python组排列和组合、二进制讲解

目录 一、排列 1、Python 的排列函数 permutations() 2、permutations() 按什么顺序输出序列&#xff08;重要⭐&#xff09; 3、易错点 二、组合 1、Python的组合函数combinations() 2、注意内容 三、手写排列和组合代码 1、手写排列代码&#xff08;暴力法&#xff…

【PWA学习】2. 使用 Manifest, 让你的 WebApp 更 Native

引言 我们知道&#xff0c;在 chrome(等一些现代浏览器)中&#xff0c;你可以将访问的网站添加到桌面&#xff0c;这样就会在桌面生成一个类似 “快捷方式” 的图标&#xff0c;当你点击该图标时&#xff0c;便可以快速访问该网站(Web App) 我们以 demo 为例&#xff0c;其添加…

无监督聚类表征学习方法之对比学习(Contrastive Learning)——simclr方法

无监督聚类表征学习方法之对比学习(Contrastive Learning)——simclr方法 1.参考论文 《A Simple Framework for Contrastive Learning of Visual Representations》 2.无监督聚类表征学习方法 主要有几种&#xff1a; ①自动编码器(AutoEncoder,AE); ②变分自编码器(Variatio…

两款开源.NET工作流引擎 Elsa 与ccflow使用比较

相对java开源的工作流程引擎.net开源的工作流程引擎相对较少&#xff0c;这里整理两款.net开源工作流引擎&#xff0c;做一下对比使用。elsa示例代码:Githubd地址&#xff1a;https://github.com/zhenl/MyElsaccflow下载地址&#xff1a;https://gitee.com/opencc/ccflowCCFlow…

Java笔记021-异常-Exception

异常-Exception看个实际问题和一段代码运行下面的代码&#xff0c;看看有什么问题->引出异常和异常处理机制package com12.exception_;/*** author 甲柒* version 1.0* title Exception01* package com12.exception_* time 2023/1/9 14:38*/ public class Exception01 {publ…