linux驱动(一):linux驱动框架

编写linux驱动先看一下驱动框架是什么样子的。

驱动编写和应用层编写有什么区别呢?

(一)首先 入口函数的问题。应用层编写我们的入口就是main函数,但在驱动编写时不是这样的,有两种情况,

1、缺省情况下

int __init init_module(void)  加载模块时的初始化函数,也就是驱动模块的入口函数

void __exit cleanup_module(void) 卸载模块时的函数,也就是卸载某个驱动时要执行的函数

2、

static int __init xxxx_init(void)  加载模块时的初始化函数,也就是驱动模块的入口函数

static void __exit xxxx_exit(void)  卸载模块时的函数,也就是卸载某个驱动时要执行的函数

上述两种情况相比,我们一般用第二种,因为第一种的名称是固定的,我们不能做更改,第二种我们可以改写xxxx为我们自己模块的名字。可以达到见文知义。

在用第二种模式时,我们要首先用固定格式声明一下:

module_init(xxxx_init);
module_exit(xxxx_exit);

来表明加载初始化函数和卸载函数。

(二)c语言的标准函数库不能使用

        驱动属于内核的一部分,我们此时还无法使用类似像printf这样的c库,但是内核会提供自己的c库,在内核中我们用printk代替printf函数。

(三)添加LICENSE声明

        linux是开源的系统,那就要我们遵守一定的规范,我们一般用GPL规范,所以在驱动编写时都要声明一下

        MODULE_LICENSE(“GPL”);

基本的区别就是这些,我们来看一个简单的驱动框架

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


MODULE_LICENSE("GPL");

static int __init demo_init(void)
{
	printk("%s,%d\n", __func__, __LINE__);

	printk("val:%d\n", obj.val);
	obj.func();


	return 0;
}

static void __exit demo_exit(void)
{
	printk("%s,%d\n", __func__, __LINE__);
}

module_init(demo_init);
module_exit(demo_exit);
完成驱动编写后,如何才能加载到内核呢?我们需要通过Makefile 生成.ko文件,一个简单的Makefile如下,这是在ubutnu下的Makefile,如果换为ARM平台下的linux需要更换源文件目录。具体解释可以看内核模块编译makefile入门。执行make即可生成模块.ko文件
$(warning KERNELRELEASE = $(KERNELRELEASE))

ifeq ($(KERNELRELEASE),)

#内核的源码路径, ?= 条件赋值, uname -r  得到内核的版本号
KERNELDIR ?= /lib/modules/$(shell uname -r)/build  

# := 立即赋值, 得到当前的绝对路径
PWD := $(shell pwd)


# -C 切换工作路径, make -c
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*

.PHONY: modules  clean

else
	  # 生成模块
       obj-m := used.o 
	
endif



下面我们来看几个驱动中常用的命令

1、加载驱动模块insmod

     将生成驱动模块.ko文件加载,

     insmod xxx.ko

     加载后就会执行xxxx_init函数

2、卸载驱动模块rmmod

     对应的卸载驱动的命令

     rmmod xxxx 注意不用带.ko

3、查看内核中的模块信息

     lsmod

4、查看模块的描述信息

     modinfo xxxx.ko

     我们可以在驱动程序添加一些辅助信息,例如作者 ,驱动描述等。

5、查看模块打印信息

     dmesg   

     printk是内核打印函数,默认模式下在中断下无法显示(当然,可以设置成打印到终端),用dmesg可以查看一下打印到内核的信息。

上述几个比较常用,有其他的我们可以以后再看。

我们把上述几个熟悉一下

insmod /rmmod/dmesg

 

加载模块后执行初始化函数,打印函数名和行号


卸载模块后执行卸载函数,打印函数名和行号

打印模块信息 modinfo


查看内核中模块信息lsmod


module为模块名称   size为模块打下  usedby 表明有几个其他文件使用

实际上lsmod是读取并分析“/proc/modules”文件,我们来看一下这个文件


内核已经加载的模块的信息也存在于/sys/module目录下,加载demo.ko后,内核中将包含/sys/moudle/demo目录,demo的目录树结构如下


除了使用insmod加载模块以外,还可以用modprobe命令来加载模块,并且使用modprobe加载模块时,会同时加载模块所依赖的其他模块。insmod必须按顺序一个一个加载模块。同样在卸载时,modprobe -r filename的方式会同时卸载该模块所依赖的模块。

模块之间的依赖关系放在/lib/modules/<kernel-version>/modules.dep文件中。实际上是在整体编译内核的时候由depmod工具生成的,该文件的格式很简单:有依赖的直接在“:”后面加上。











  • 47
    点赞
  • 312
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Linux驱动程序支持多种驱动框架,以下是其中的一些: 1. Char驱动框架:Char驱动框架Linux内核中最常用的驱动框架。它用于实现字符型设备驱动程序,例如串口、键盘、鼠标等。 2. Block驱动框架:Block驱动框架用于实现块设备驱动程序,例如硬盘、闪存等。它提供了一种标准的方式来管理块设备和实现块设备操作。 3. Net驱动框架:Net驱动框架用于实现网络设备驱动程序,例如网卡、无线网卡等。它提供了一种标准的方式来管理网络设备和实现网络设备操作。 4. USB驱动框架:USB驱动框架用于实现USB设备驱动程序,例如USB存储设备、USB打印机等。它提供了一种标准的方式来管理USB设备和实现USB设备操作。 5. PCI驱动框架:PCI驱动框架用于实现PCI设备驱动程序,例如显卡、声卡、网卡等。它提供了一种标准的方式来管理PCI设备和实现PCI设备操作。 6. MTD驱动框架:MTD驱动框架用于实现闪存设备驱动程序,例如NOR Flash、NAND Flash等。它提供了一种标准的方式来管理闪存设备和实现闪存设备操作。 除了以上列举的驱动框架Linux还支持其他一些驱动框架,例如I2C驱动框架、SPI驱动框架、GPIO驱动框架等。每个驱动框架都提供了一种标准的方式来管理设备和实现设备操作,开发者可以根据具体的硬件和需求选择和使用适当的驱动框架

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值