$2$驱动模块

news2024/10/6 4:07:09

目录

1.驱动模块(驱动程序的框架)

2.内核中的打印函数(编写第一个驱动程序)

Source Insight 使用:

打印函数编写

分析

3.驱动的多文件编译

4.模块传递参数

安装好驱动之后如何传参?

 多驱动之间调用(导出符号表)

具体过程

5.字符设备驱动

字符设备驱动的注册

 具体过程:

具体代码

总结归纳:

手动创建设备文件


1.驱动模块(驱动程序的框架)

入口(安装):资源的申请

出口(卸载):资源的释放

许可证:GPL

#include <linux/init.h>
#include <linux/module.h>
//声明   //static 是为了防止别人的驱动和你重名 
static int __init hello_init(void)    //入口
{

}
static void __exit hello_exit(void)   //出口
{

}
//告诉内核驱动的入口
module_init(hello_init);
//告诉内核驱动的出口
module_exit(hello_exit);
MODULE_LICENSE("GPL");    //许可证

Makefile

KERNELDIR:= /lib/modules/$(shell uname -r)/build/  //ubuntu 内核目录
#KERNELDIR:= /home/linux/kernel/kernel-3.4.39/    //开发板内核目录
PWD:=$(shell pwd)
all: 
    make -C $(KERNELDIR) M=$(PWD) modules
clean:
    make -C $(KERNELDIR) M=$(PWD) clean
obj-m:=hello.o 	

具体过程:

vi Makefile

 ls

 

 

 

 

 更改

 

 

 

 

 vi hello.c

make

 

 

 

 SI3US-361500-17409

2.内核中的打印函数(编写第一个驱动程序)

Source Insight 使用:

 

 

 

 

 

 

 

 

打印函数编写

分析

--------------------------------------打印级别--------------------------------------
#define KERN_EMERG	"<0>"	/* system is unusable			*/
#define KERN_ALERT	"<1>"	/* action must be taken immediately	*/
#define KERN_CRIT	"<2>"	/* critical conditions			*/
#define KERN_ERR	"<3>"	/* error conditions			*/
#define KERN_WARNING	"<4>"	/* warning conditions			*/
#define KERN_NOTICE	"<5>"	/* normal but significant condition	*/
#define KERN_INFO	"<6>"	/* informational			*/
#define KERN_DEBUG	"<7>"	/* debug-level messages			*/
y@y-virtual-machine:~/linux6818/demo$ cat /proc/sys/kernel/printk
   4              4	                 1	            7     

终端的级别   消息的默认级别   终端的最大级别   终端的最小级别  
#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
--------------------------------打印函数---------------------------------------------
printk(KERN_ERR "BFS-fs: %s(): " format, __func__, ## args)
功能:消息打印
参数:
   第一个参数:打印的级别
   第二个参数:打印的内容
   第三个参数:和printf一样,需要打印的参数

 ubuntu级别

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
static int __init hello_init(void)//入口
{
  printk(KERN_ERR "hello word\n");
  return 0;
}
static void __exit hello_exit(void)//出口
{
  printk(KERN_ERR "baibai\n");
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

 安装卸载无反应,因为ubuntu基于linux内核做的开发

PM:

 

dmesg (查看消息的回显) dmesg -c (查看回显并清空)dmesg -C (清空回显)

 

 

 可以不写KERN _ERR 以默认的级别显示

重点:

ctrl+Alt+F5 (进入虚拟控制台)ctrl+Alt+F7(退出虚拟控制台)-》有的退出是F2
sudo insmod  hello.ko(安装驱动)sudo rmmod  hello(卸载驱动)
 dmesg (查看消息的回显)  dmesg -c  (查看回显并清空)dmesg -C  (清空回显)
cat /prod/sys/kernel/printk 
(查看ubuntu终端显示级别 消息默认级别 消息最大级别  消息最小级别)
su root echo 4 3 1 7 > /proc/sys/kernel/printk
(修改ubuntu终端显示级别 消息默认级别 消息最大级别  消息最小级别)
echo 4 3 1 7 > /proc/sys/kernel/printk
(修改开发板)
= 赋值 需要等待其他文件全部执行完,才执行调用的 
:= 立即赋值
+= 附加赋值
?= 询问变量之前是否被赋值过 如果赋值过,本次赋值不成立,否则成立

3.驱动的多文件编译

hello.c  add.c
	 Makefile
	 obj-m:=demo.o
	 demo-y+=hello.o add.o
	最终生成demo.ko文件	

 vi makefile

增添完后 make

然后make clean

4.模块传递参数

module_param(name, type, perm)    //驱动安装时候的安装路径,或者安装时配置的参数

功能:接收命令行传递的参数

参数:

name: 变量的名字  type:变量的类型  perm:权限 0664 0775 
#include <linux/init.h>
#include <linux/module.h>
int a=10;
module_param(a,int,0664);                   
static int __init hello_init(void)
{
 printk("sum= %d\n",a);
 return 0;
}
static void __exit hello_exit(void)
{
 printk(KERN_ERR"bai");                
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

 替换Linux6818/demo的hello.c文件 然后进行修改之前的双编译Makefile 即vi Makefile

 完事后 进行make

 

 

 完事后 卸载驱动 sudo rmmod hello

传递两个参数程序

int a=10;
module_param(a,int,0664);    
int b=10;
module_param(b,int,0664);    

问:安装时怎么区分a和b的作用,自己写的知道那如果移植其他厂商的呢比如LCD屏

使用modinfo hello.ko查看,且需要程序里使用如下函数进行配置

 无法看出哪个是什么功能 无法提示

MODULE_PARM_DESC(_parm, desc)
功能:对变量的功能进行描述
参数:
	@_parm:变量
	@desc :描述字段
int a=10;
module_param(a,int,0664);
MODULE_PARM_DESC(a,"light");
short b=123;
module_param(b,short,0664);
MODULE_PARM_DESC(b,"clour");
char c='c';
 module_param(c,byte,0664);
 MODULE_PARM_DESC(c,"light_c");
 char *d=null;
 module_param(d,charp,0664);
  MODULE_PARM_DESC(d,"clour");
 static int __init hello_init(void)
{ 
    printk("sum= %d\n",a);
    printk("sum= %d\n",b);
    printk("sum= %c\n",c);
    printk("sum= %s\n",d);                                                                                                                                                                                 
return 0;
}
static void __exit hello_exit(void)
 {
  printk(KERN_ERR"bai");
}
 module_init(hello_init);
 module_exit(hello_exit);
 MODULE_LICENSE("GPL");

vi hello.c

 

 

int a=10;

int b=0;

module_param(a, int, 0664) ;

module_param(b, int, 0664) ;

MODULE_PARM_dESC(a,"light");

MODULE_PARM_dESC(b,"color");

sudo insmod hello.ko a=20

make

modinfo hello.ko

sudo insomd hello.ko a=30 b=24

sudo dmesg -c

数组传参:

module_param_array(name,type,nump,perm)
功能:接收命令行传递的数组
参数:
name:数组名 type :数组类型  nump:参数的个数,变量的地址 perm 权限
int ww[10]={0}; 
int num;
module_param_array(ww,int,&num,0664)
static int __init hello_init(void)
{
    int i;
    for(i=0;i<num;i++)
    {
     printk("ww[%d]=%d\n",i,ww[i]);
    }
}

sudo insmod hello.ko ww=1,2,3,4,5

具体过程:

 

 

 

 

int ww[10]={0}; 
int num;
module_param_array(ww,int,&num,0664)
static int __init hello_init(void)
{
    int i;
    for(i=0;i<num;i++)
    {
     printk("ww[%d]=%d\n",i,ww[i]);
    }
}

make

sudo insmod hello.ko ww=1,2,3,4,5

安装好驱动之后如何传参?

1.lsmod查看驱动名字

2.找路径 /sys/module/驱动模块的名字/parameters

3.修改 -》su root -》echo 需要改为多少>需要修改的参数名

4.cat 需要修改的参数名(查看是否修改成功)

 多驱动之间调用(导出符号表)

假如有两个驱动模块,modul1和modu2 。这两个是可以调用的

cp  ../day1/module  .  -a    拷贝module到当前目录下

makdir export   mv module/  export/ 

mv module/   A 重命名moudule为A

cp A B -a  拷贝一份并命名为B

#include <linux/intt.h>
#include <linux/module.h>
int add(int a,int b)
{
 return (a+b);
}
EXPORT_SYMBOL_GPL(add);//导出符号表
static int __init hello_init(void)
{
 return 0;
}
staic int __exit hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

进入B,mv hello.c demo.c改下名字

然后vi打开

extern int add(int a,int b);
static int __init hello_init(void)
{
    printk("sum = %d\n",add(10,345));
}

编译

  make  

 发现报错,提示add没有定义

 所以在执行之前把A里面大M开头文件复制到当前目录下   

mv  cp  ../A/Module.symvers

然后再make

安装:

 先安装提供者 sudo insmod hello.ko

 再安装调用者 sudo insmod  demo.ko

查看信息:dmesg

卸载:

先卸载 demo.ko  再卸载 hello.ko

具体过程

cp -r /

 

 

vi add.c

 

 make

 

 vi hello.c

 

5.字符设备驱动

APP层    ---- 读写操作 ----→

                                     open打开一个文件 --→{ open=hello、read=buf、write=ubuf、close=hello}

内核层    ---- 读写文件 ----→

   |

   v

硬件层    ---- GPIO输出 ----→     LED灯    

字符设备驱动的注册

   int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

功能:注册一个字符设备驱动

参数:

@major:主设备号  

  :如果你填写的值大于0,它认为这个就是主设备号

  :如果你填写的值为0,操作系统给你分配一个主设备号   

@name :名字    cat /proc/devices 查看设备名和主设备号

@fops :操作方法结构体

返回值:major>0 ,成功返回0,失败返回错误码(负数) (vi -t EIO 可以查看错误码)

major=0,成功主设备号,失败返回错误码(负数)      

void unregister_chrdev(unsigned int major, const char *name)

功能:注销一个字符设备驱动

参数:

@major:主设备号

@name:名字

返回值:无

 具体过程:

 开始注册,起一个变量

 

 

 

具体代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
int major=0;
#define CNAME "hello"
ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
{
   printk("this is read");
   return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *user, size_t, loff_t *loff)
{
   printk("this is write");
   return 0;
}
int mycdev_open (struct inode *inode, struct file *file)
{
   printk("this is open");
   return 0;
}
int mycdev_release (struct inode *inode, struct file *file)
{
   printk("this is close");
   return 0;
}
	
const struct file_operations fops={
   .open=mycdev_open,
   .read=mycdev_read,
   .write=mycdev_write,
   .release=mycdev_release,
};

static int __init hello_init(void)//入口
{
  major=register_chrdev(major,CNAME,&fops);
  if(major<0)
  {
   printk("register chrdev error");
  }
  return 0;
}
static void __exit hello_exit(void)//出口
{
  unregister_chrdev(major,CNAME);
}
module_init(hello_init);//告诉内核驱动的入口
module_exit(hello_exit);//告诉内核驱动的出口
MODULE_LICENSE("GPL");

总结归纳:

字符设备驱动:

 1、注册驱动register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

major=0  自动分配设备号  name:驱动的名字   fops:结构体

 2、声明结构体-》注册驱动时第三个参数

 3、open、read、write、release-》按照内核的格式自己写的

 4、把自己写的这些函数->给到结构体里-》.open .read .write .release

 5、注销设备驱动

手动创建设备文件

cat /proc/devices 查看主设备号

sudo  mknod hello(路径:是任意的)   c/b (C代表字符设备 b代表块设备) 主设备号   次设备号

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

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

相关文章

智能照明控制系统在现代建筑工程中的应用 安科瑞 许敏

摘要&#xff1a; 文章分析了在现代建筑工程中智能照明控制系统所具有的优越性&#xff0c;并对如何解决该技术在实际应用中遇到的问题提出了看法与建议。 关键词&#xff1a;智能照明 控制系统 应用节能 引言 随着人们的物质和精神生活水平不断提高&#xff0c;对生活的追求…

MMC整流器Matlab仿真模型子模块个数N=18(含技术文档)

资源地址&#xff1a; MMC整流器Matlab仿真模型子模块个数N&#xff1d;18&#xff08;含技术文档&#xff09;资源-CSDN文库 模型介绍&#xff1a; 1.MMC工作在整流侧&#xff0c;子模块个数N&#xff1d;18&#xff0c;直流侧电压Udc&#xff1d;25.2kV&#xff0c;交流侧…

算法设计与分析期末复习(二)

动态规划 基本思想&#xff1a;把求解的问题分成许多阶段或多个子问题&#xff0c;然后按顺序求解各个子问题。**前一个子问题的解为后一个子问题的求解提供了有用的信息。**在求解任何一子问题时&#xff0c;列出各种可能的局部解&#xff0c;通过决策保留那些有可能达到最优…

Linux面试题汇总

Linux面试题汇总 网络拓展Linux 概述什么是LinuxUnix和Linux有什么区别&#xff1f;什么是 Linux 内核&#xff1f;Linux的基本组件是什么&#xff1f;Linux 的体系结构BASH和DOS之间的基本区别是什么&#xff1f;Linux 开机启动过程&#xff1f;Linux系统缺省的运行级别&#…

javaScript蓝桥杯----外卖给好评

目录 一、介绍二、准备三、⽬标四、代码五、完成 一、介绍 外卖是现代⽣活中必备的⼀环。收到外卖后&#xff0c;各⼤平台软件常常会邀请⽤户在⼝味&#xff0c;配送速度等多个⽅⾯给与评分。在 element-ui 组件中&#xff0c;已经有相应的 Rate 组件&#xff0c;但是已有组件…

前端052_单点登录SSO_单点退出系统

单点退出系统 1、 需求分析2、EasyMock 添加退出系统模拟接口3、定义Api调用退出接口4、定义 Vuex 退出行为1、 需求分析 所有应用系统退出,全部发送请求到当前认证中心进行处理,发送请求后台删除用户登录数据,并将 cookie 中的用户数据清除。 2、EasyMock 添加退出系统模拟…

大数据分析案例-基于LightGBM算法构建银行客户流失预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

第四章:运算符

第四章&#xff1a;运算符 4.1&#xff1a;算术运算符 ​ 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达值&#xff0c;对数值或表达式进行加()、减(-)、乘(*)、除(/)、取模(%)运算。 运算符名称作用示例加法运算符计算两个值或表达式的和SE…

chatgpt赋能python:Python如何遍历文件:一篇完整的指南

Python如何遍历文件: 一篇完整的指南 在进行文件操作时&#xff0c;遍历文件是相当普遍的需求。Python中提供了多种方法来遍历文件夹和文件&#xff0c;包括os模块&#xff0c;glob模块和os.walk方法。这篇文章将会介绍这些方法及其应用。 什么是遍历文件&#xff1f; 遍历文…

使用 ConstraintLayout

ConstraintLayout解析 1.前言2.了解ConstraintLayout3.基本用法3.1 看一个布局3.2再看一个布局 1.前言 你是不是一直不敢用ConstraintLayout&#xff0c;是以为属性太多太复杂&#xff1f;你心理上的惰性&#xff0c;畏惧它。它其实很好用很强大&#xff0c;如果要用就需要一个…

Day_40关于图的总结

一. 实际问题的抽象与建模 如果我们需要研究一个实际问题&#xff0c;首先第一步就是对这个实际问题进行抽象&#xff0c;抽象是从众多的事物中抽取出共同的、本质性的特征&#xff0c;而舍弃其非本质的特征的过程。具体地说&#xff0c;抽象就是人们在实践的基础上&#xff0c…

Java中的金钱陷阱

前言 有多少小伙伴是被标题 骗 吸引进来的呢&#xff0c;我可不是标题党&#xff0c;今天的文章呢确实跟”金钱“有关系。 但是我们说的不是过度追求金钱而掉入陷阱&#xff0c;而是要说一说在Java程序中&#xff0c;各种跟金钱运算有关的陷阱。 日常工作中我们经常会涉及到…

chatgpt赋能python:Python字幕滚动:如何让你的视频内容更吸引人

Python字幕滚动&#xff1a;如何让你的视频内容更吸引人 如果你是一位视频创作者&#xff0c;你可能知道如何通过字幕来增加你的视频的吸引力。Python提供了一种简单且高效的方法来制作字幕滚动。字幕滚动是指将文字逐个显示在视频下方&#xff0c;以帮助观众跟上视频的进展。…

让我们彻底了解Maven(一)--- 基础和进阶

Maven大家都很熟悉&#xff0c;但是我们很多人&#xff0c;对它其实都是似乎很熟&#xff0c;但是又好像不熟悉的感觉&#xff0c;包括我&#xff0c;今天咱们就一起来彻底了解Maven的所有功能&#xff0c;我们从入门&#xff0c;到原理剖析&#xff0c;再到实践操作&#xff0…

chatgpt赋能python:Python如何遍历列表并提取

Python如何遍历列表并提取 在Python编程语言中&#xff0c;列表是一种非常常见的数据类型。它是一个有序的集合&#xff0c;可以存储多个元素&#xff0c;可以是任何类型的数据&#xff0c;例如整数、字符串、布尔值等等。遍历一个列表并提取其中的元素是一个基本的操作&#…

测试用例设计方法——错误猜测法

很多软件测试从业者用到的黑盒测试用例设计方法大多是等价类划分法、边界值分析法、判定表法、因果图法和正交试验法等&#xff0c;其实还有一种方法不得不提到&#xff0c;那就是错误猜测法&#xff0c;这对资深测试人员尤为重要。因为随着在产品测试的实践中对产品的了解和测…

MySQL目录结构与源码

MySQL目录结构与源码 前言一、主要目录结构二、MySQL 源代码获取 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注博主&#xff01;也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff…

Linux命令学习之文本查看命令cat、head和tail

for i in {1..100} do echo $i >> good.txt done把1到100写入到good.txt文件中。接下来使用good.txt这个文件来演示查看文本查看命令。 cat man cat可以看一下帮助使用说明&#xff0c;按q可以退出。 cat是连接文件并把文件内容输出到标准输出上。cat good.txt就可以…

Mirai 僵尸网络变体向 RCE、DDoS 开放 Tenda、Zyxel Gear

Mirai 僵尸网络的一个变体利用四种不同的设备漏洞将流行的基于 Linux 的服务器和物联网 (IoT) 设备添加到可以进行基于网络的攻击&#xff08;包括分布式拒绝服务 (DDoS) 攻击&#xff09;的僵尸网络中。 Palo Alto Networks 的 Unit 42 的一个团队观察到这个变体&#xff0c;…

【利用AI让知识体系化】Webpack 相关配置技巧

文章目录 章节一&#xff1a;了解 WebpackWebpack 是什么&#xff1f;为什么使用 Webpack&#xff1f;Webpack 的基本概念Webpack 的核心概念和实现原理 章节二&#xff1a;安装和配置 Webpack安装 Webpack配置 WebpackWebpack 的常用配置项 章节三&#xff1a;Webpack 的插件和…