驱动开发概念详解

2023-09-13 19:28:21

1、什么是驱动

        能够驱使硬件实现特定功能的软件代码,可以根据驱动程序是否依赖于系统内核将其分为裸机驱动和系统驱动

1.1裸机驱动

        编写的驱动代码中没有进行任何内核相关的API调用,开发者查询资料配置寄存器完成硬件相关控制,不依赖于系统内核,由开发者独立完成,相对而言比较简单。

1.2系统驱动

        系统驱动指的是编写的驱动代码中需要调用系统内核中提供到的各自API,驱动最终也会加载到系统内核生效。系统驱动开发者无法独立完成,需要依赖于系统内核,基于系统驱动实现的硬件功能也更加复杂

进程上下文切换概念:当进程进行系统调用时,进程访问到的资源从用户空间到内核空间,就叫上下文切换。

内核层向上提供的接口类型:

文件管理、内存管理、进程管理、网络管理(socket)、设备管理(设备驱动的管理)

设备驱动的分类:

linux设备驱动的类型要根据设备的类型进行驱动,系统将其分为字符设备、块设备、网卡设备

字符设备:能够以字节流的形式进行顺序访问的设备叫做字符设备(鼠标、键盘、led灯)

块设备:能够以块(512字节)为单位进行随机访问的设备叫做块设备(磁盘)

网卡设备:进行网络通信时使用网卡设备实现,网卡设备的数据读写基于套接字实现

2、linux内核模块化编程

1、内核模块化的意义

不同于应用程序,驱动是加载到内核空间中的,所以需要内核模块的编程框架编写驱动代码

2、内核模块的三要素

内核模块由三部分组成:入口、出口、许可证

入口:内核模块安装时执行,主要负责资源的申请工作

出口:卸载内核模块时执行、主要负责资源的释放工作

许可证:声明内核模块遵循GPL协议

3、内核模块编程

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

//入口函数  安装内核模块时执行
static int __init mycdev_init(void)
{
    //static用于限制入口函数只能在当前文件中使用
    //int指定函数的返回值为int类型,返回值一定要加,不然编译报错
    //mycdev_init,入口函数的函数名,可以自己修改
    //void表示这个函数参,当函数没有参数时一定在参数列表中加void,不然会报错
    /*在ubuntu中的内核目录下索引指定的API时,可以在内核顶层目录下输入ctags -R
            接着使用vi -t 接口名即可索引
    */
    //#define __init        __section(".init.text")
    //__init用于向编译器声明当前mycdev_init函数加载到.init.text段
    //.init.text段指定在内核的链接脚本文件vmlinux.lds中
    
    return 0;
}

//出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{
    //#define __exit          __section(".exit.text")
}
//用于声明当前内核模块入口函数的地址
module_init(mycdev_init);
//用于声明当前内核模块出口函数的地址
module_exit(mycdev_exit);
//声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL"); 

4、内核模块的编译

4.1编译内核模块的命令

make modules

4.2内部编译(静态编译)

需要依赖于内核源码树进行编译

  • 将编写的内核模块源码存放到linux内核指定目录下
  • 修改该目录下的kconfig文件,添加当前模块文件的选配项
  • 执行make menuconfig,将当前内核模块源码的选配项选配为【M】
  • 执行make menuconfig进行模块化编译

 外部编译(动态编译)

不需要依赖于内核源码树,在编译时只需要编译当前内核模块文件即可,外部编译需要自己手写当前内核模块编译的Makefile

4.3编写动态编译的内核模块的Makefile

#定义变量存放内核源码顶层路径
#KERNELDIR:= /home/ubuntu/linux-5.10.61       #用于编译生成ARM架构的模块
KERNELDIR := /lib/modules/$(shell uname -r)/build  #用于生成x86架构的模块
#定义变量保存模块化编译的文件的路径
PWD:= $(shell pwd)
all:
#make modules是模块化编译的命令
#make -C $(KERNELDIR)表示读取KERNELDIR路径下的Makefile进行make编译
#M=$(PWD)指定模块化编译的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean: #编译清除
    make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=demo.o  #指定将demo.o独立链接生成内核模块文件

 通用版本的Makefile

modname?=demo  #给定一个默认的模块名
arch?=arm #给定一个架构的模块名
ifeq ($(arch),arm)#判断要编译的架构进而使用不同的Makefile规则进行编译
#定义变量存放内核源码顶层路径
KERNELDIR:= /home/ubuntu/linux-5.10.61   #用于编译生成ARM架构的模块
else
KERNELDIR := /lib/modules/$(shell uname -r)/build  #用于生成x86架构的模块
endif

#定义变量保存模块化编译的文件的路径
PWD:= $(shell pwd)
all:
#make modules是模块化编译的命令
#make -C $(KERNELDIR)表示读取KERNELDIR路径下的Makefile进行make编译
#M=$(PWD)指定模块化编译的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean: #编译清除
    make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=$(modname).o  #指定将demo.o独立链接生成内核模块文件

5、内核模块相关指令

安装内核模块:

sudo insmod ****.ko

查看被安装的内核模块

lsmod

卸载内核模块

sudo rmmod ***

查看内核模块相关信息

modinfo ****.ko

 内核中的消息打印函数:

printk(消息输出级别 "格式控制符",输出列表);

 查看消息默认级别

终端输入 cat /proc/sys/kernel/printk查看

终端默认级别 消息默认级别 终端支持的消息最高级别 终端支持消息的最低级别

dmesg命令的使用

功能:输出从内核启动到当前时刻开始所有的打印信息

dmesg -c/dmesg -C: 清除当前dmesg的buf中保存的所有打印信息

6、linux内核模块传参

内核模块传参

内核模块传参指的是安装模块时在命令行给内核模块中的变量传递数值

ex:insmod demo.ko a=100 

内核模块传参的意义

通过内核模块传参的使用,我们可以对内核模块的一些属性进行修改,让其适配多种不同的硬件

 内核模块传参实现的相关API

module_param(name,type,perm)
//声明可以通过命令行传参的变量信息
参数:name 要进行命令行传参的变量名
      type:要进行命令行传参的变量类型
/ * Standard types are:
             byte(单字节类型), hexint, short, ushort, int, uint, long, ulong
           charp: a character pointer(char *)
           bool: a bool, values 0/1, y/n, Y/N.
           invbool: the above, only sense-reversed (N = true).
 */
     perm:文件权限,当使用module_param函数声明要传参的变量时,会在/sys/module/当前内核模块名/parameters/目录下生成一个以当前变量名为名的文件,文件的权限就是perm和文件权限掩码运算得到,文件的数值时变量的值
2.MODULE_PARM_DESC(变量名, 对变量的描述)
功能:添加对要传参的变量的描述,这个描述可以通过modinfo ***.ko查看到

更多推荐

【计算机网络】传输层协议——TCP(中)

文章目录1.三次握手三次握手的本质是建立链接,什么是链接?整体过程三次握手过程中报文丢失问题为什么2次握手不可以?为什么要三次握手?2.四次挥手整体过程为什么要等待2MSL3.流量控制4.滑动窗口共识滑动窗口的一般情况理解滑动窗口滑动窗口的特殊情况1.三次握手SYN:是一个连接请求的报文(三次握手),发送的是TCP报头

IP风险查询:抵御DDoS攻击和CC攻击的关键一步

随着互联网的普及,网络攻击变得越来越普遍和复杂,对企业和个人的网络安全构成了重大威胁。其中,DDoS(分布式拒绝服务)攻击和CC(网络连接)攻击是两种常见且具有破坏性的攻击类型,它们可以对网络基础设施和在线业务造成重大损害。为了抵御这些攻击,IP风险查询变得至关重要。DDoS攻击简介:DDoS攻击旨在通过同时发送大量网

大事件!请注意!AIGC正在疯狂“污染”学术界

原创|文BFT机器人2023年被称为AIGC元年,大模型也成为重中之重,市场预期其创新性甚至远大于移动互联网。AIGC或进一步解放生产力,帮助企业降本增效,影响并改变着互联网的获取信息和内容产出方式。以ChatGPT为代表的新一代人工智能技术迅猛发展,它以强大的语义理解能力、逻辑推理能力和多轮对话能力快速席卷全球,各类

分布式之消息队列精讲

小A,工作于传统软件行业(某社保局的软件外包公司),每天工作内容就是和产品聊聊需求,改改业务逻辑。再不然就是和运营聊聊天,写几个SQL,生成下报表。又或者接到客服的通知,某某功能故障了,改改数据,然后下班部署上线。每天过的都是这种生活,技术零成长。小B,工作于某国企,虽然能接触到一些中间件技术。然而,他只会订阅/发布消

GAN初识

1.生成对抗网络GAN简介1.1生成器G(Z)接受随机噪声Z作为输入生成仿品,并训练自己去欺骗判别器D,让D以为G(Z)产生的任何数据都是真实的。1.2判别器D(Y)可以基于真品和仿品来判断仿造品的仿真程度,通常值越靠近0表示越真实(靠近1表示仿造)。其目标是:使每个真实数据分布中的图像的D(Y)值最大化,并使真实数据

语义噪声的解释

《RobustSemanticCommunicationsAgainstSemanticNoise》定义语义噪声是一种导致误解语义信息和解码错误的噪声。它导致传输的语义符号和接收到的语义符号之间存在差异,在语义编码、数据传输和语义解码阶段都可能被引入[1]分类不同源(文本和图像等)产生语义噪声的原因是不同的:文本文本中

时序预测 | MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络时间序列预测

时序预测|MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络时间序列预测目录时序预测|MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料预测效果基本介绍MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积

Android Studio插件版本与Gradle 版本对应关系

关于作者:CSDN内容合伙人、技术专家,从零开始做日活千万级APP。专注于分享各领域原创系列文章,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。目录一、导读二、概览三、Gradle各版本对应关系3.1Gradle版本3.2插件版本3.3AndroidGradle插件和AndroidStudio兼容

亚马逊云科技创新加速周:以数智化手段加速中国企业出海之旅

近年来,越来越多的中国企业正在走向国际市场,中国企业如何在出海浪潮下稳重求进?9月18日-9月22日,新一期亚马逊云科技合作伙伴加速周将为您带来“智荟出海”专题。“智荟出海计划”是亚马逊云科技发布的一项合作计划,旨在全方位资源赋能合作伙伴,以数智化手段加速中国企业的出海之旅。亚马逊云科技将携手25家合作伙伴,倾情打造为

局部变量,全局变量与内存

本文会使用IDA分析局部变量,全局变量在内存的存储目录使用IDA分析局部变量使用IDA分析全局变量总结使用IDA分析局部变量#include<stdio.h>intmain(){intnNum=1;floatfNum=2.5;charch='A';printf("int%d,float%f,char%c",nNum,f

再次理解Android账号管理体系

目录✅0.需求📂1.前言🔱2.使用2.1账户体系前提2.2创建账户服务2.3操作账户-增删改查💠3.源码流程✅0.需求试想,自己去实现一个账号管理体系,该如何做呢?——————————最近有遇到这样一个需求:AR眼镜只支持同时与一个手机绑定,即:AR眼镜已与手机绑定过的话,不再支持与其他手机绑定;如要绑定其他手机

热文推荐