Linux驱动开发-01基础框架与测试

基本构成

驱动是用户开发的基础,在linux系统上进行软件设计,几乎都是调用驱动的函数对低层进行操作,实现相应的功能。这就表明驱动开发是给上层开发者提供接口的一种开发,其重要性不言而喻。驱动也分类别,字符设备驱动(点灯、I2C、SPI、音频)、块设备驱动(这里的块主要指的是存储块,所以主要是:EMMC、NAND、SD、U盘)和网络设备驱动(USB、wifi),这三种类别也有交叉,比如usb使用某些功能的时候属于字符驱动,使用网络功能时又是网络驱动。驱动开发必须遵循一定的规则,比如一些初始、加载、使用的函数名是固定的,这是为了给linux上层的无平台差异性进行的限制(自己的理解,大概就是规范化的意思)。

编写驱动时,open、close、write 和 read 等这些函数是必须要实现的,而这里个函数的定义是在linux内核源码的include/linux/fs.h文件中进行定义的,所以编写驱动必须用到linux源码才能进行编译工作,主要用到的是linclude目录下的头文件(根目录下的、arch/arm下的、arch/arm/include/generated/下的)。

驱动的加载和卸载函数也是固定的,分别是module_init(xxx_init);module_exit(xxx_exit); 参数为加载函数

驱动编译完成以后扩展名为.ko,驱动的加载命令有insmod(简单,依赖需要自己加载)和 modprobe(严谨,自动加载依赖),modprobe 命令默认会去/lib/modules/<kernel-version>目录中查找模块。(有的开发板默认没有此文件夹,需要自己创建,执行modprobe命令报错时,需要执行)

  • 编写驱动中不能使用printf(运行于用户态),而是使用printk(运行于内核),printk具有不同的优先级
  • 编写驱动的makefile,驱动的Makefile会调用linux源码中的makefile,详情见正点P1046

Linux 应用程序对驱动程序的调用

image-20220406145630200

Linux 内核驱动操作函数声明集合所在的位置:include/linux/fs.h中的file_operations 结构体

驱动加载流程

  1. 使用modprobe进行驱动加载
  2. 此时提示无法打开“modules.dep”
  3. 针对上一步骤执行depmod生成文件
  4. lsmod查看当前系统已经加载的模块

驱动流程

参数为初始函数
在初始函数中注册
驱动加载
注册字符设备
结构体实现
构建结构体方法函数
驱动注销
驱动卸载

总体流程如上图所示

一个驱动主要由三个函数构成:

  1. int __init xxx_init**(void)** 驱动入口函数,也就是上面的初始函数(也就是module_init所传入的函数)
  2. void __exit xxx_exit**(**void)驱动出口函数,也就是上面的驱动卸载(也就是module_exit所传入的函数)
  3. register_chrdev()

驱动模块的加载与卸载

驱动的运行方式有两种,一种是直接写入Linux内核,另一种是以模块的形式,通过insmod命令加载驱动直接写入内核,如果修改的话需要重新编译内核,这很麻烦,所以我们写驱动一般采用第二种方式。

驱动加载所需要的函数如下:

module_init(xxx_init)注册模块
module_exit(xxx_exit)卸载模块

上述函数需要传入的即为驱动的初始化函数

设备的注册与注销

在初始化函数中,我们需要进行设备的注册,实现注册需要调用函数register_chrdev()(还有其他函数,这里用这个命令是因为作为新手简单),函数的第一个参数是设备号,“cat /proc/devices”可以查看当前已经被使用掉的设备号,设备号不能重复。

设备号申请命令:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

设备的注销是通过函数unregister_chrdev进行注销

设备操作函数的实现

当用户编写应用程序时调用的设备函数是固定的(例如open、read、write、release),这些函数在file_operations 结构体中被声明,

在编写设备驱动时,需要对结构体进行实例化(例如:static struct file_operations test_fops,test_fops就是实例化)

注册函数:static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

注销函数:static inline void unregister_chrdev(unsigned int major, const char *name)

  • major:主设备号,Linux 下每个设备都有一个设备号,使用命令cat /proc/devices查看已经使用的设备号
  • name:设备名字
  • fops:结构体 file_operations 类型指针,指向设备的操作函数集合变量

具体的例子如下:

static struct file_operations test_fops = {
 .owner = THIS_MODULE, //设备名称
 .open = chrtest_open,//具体实现open操作的函数
 .read = chrtest_read,
 .write = chrtest_write,
 .release = chrtest_release,
 };
static int chrtest_open(struct inode *inode, struct file *filp)
{
    return 0;
}

添加LICENSE信息

上述操作我们基本把驱动程序的框架搭建完成,现在就差一步,把LICENSE信息和作者信息添加到驱动中,其中 LICENSE 是必须添加的,否

则的话编译的时候会报错。

具体函数如下:

MODULE_LICENSE("GPL") //添加模块 LICENSE 信息
MODULE_AUTHOR("liming") //添加模块作者信息

驱动安装与测试

驱动安装

函数

驱动通过编译将产生.ko文件,即驱动文件,然后我们把此文件放入文件夹/lib/modules/4.1.15 (4.1.15此处应修改为自己的内核版本号)

然后通过函数insmod或modprobe加载驱动,第一次加载驱动可能会报错,提示无法打开“modules.dep”,此时我们需要输入命令depmod即可,然后再输入加载驱动函数。

接下来我们通过命令lsmod查看当前系统中存在的模块,然后再输入cat /proc/devices查看有没有我们的设备(我们的设备名为register_chrdev()函数中的第二个参数)

通过上述步骤确保我们驱动加载完成,接下来需要进行创建设备节点文件,驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操作这个设备节点文件来完成对具体设备的操作(此步骤可以在驱动程序中实现),

我们输入命令mknod /dev/chrdevbase c 200 0进行创建节点文件。

  • chrdevbase :驱动名称
  • c:表示这是个字符设备
  • 200:设备的主设备号
  • 0:设备的次设备号

有两种命令可以加载驱动模块:insmod和 modprobe,

函数说明
insmod [驱动]加载函数,不能解决依赖
modprobe加载函数,自动加载依赖模块
rmmod驱动模块卸载,不删除依赖
modprobe驱动模块卸载,也删除依赖

驱动测试

驱动的测试一般通过编写linux应用程序,然后调用此驱动进行测试,在函数编写过程中,会使用open、write、close等函数,这些函数的详细用法可以通过man [1] [命令]进行查看(1代表在驱动函数中查找次命令,此处也有234,不过查询的域不同,具体操作请百度)

Linux设备号

前面说到驱动需要有一个设备号,Linux 提供了一个名为 dev_t 的数据类型表示设备号,dev_t 定义在文件 include/linux/types.h 里面。

dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型,其中高 12 位为主设备号,低 20 位为次设备号。

设备号的申请

  1. 静态分配,上面说的方式就是静态分布
  2. 动态分配设备号:调用函数alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)进行分配
  • dev:申请到的设备号
  • baseminor:次设备号的起始地址,目前还没碰到次设备号所以一般为0
  • count:申请的设备号的数量
  • name:设备名字
  • from:要释放的设备号
  • count:从第一个参数开始,要释放的数量,一般为1

对应的释放设备号:void unregister_chrdev_region(dev_t from, unsigned count),参数解释如上。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚定的大胆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值