【Linux驱动编程】多个源文件(platform driver)编译成一个模块

platform 驱动

  linux驱动最开始采用的是纯驱动的写法,驱动工程师只需实现一个功能驱动(driver),所有功能都集中在这个驱动。接着linux内核将设备(device)和驱动(driver)分离,引入了platform总线驱动框架,内核实现platform总线,驱动工程师实现platform deviceplatform driver,方便内核管理驱动和提升驱动开发效率。到后来,linux内核将板级信息剥离,不再将板级信息编译到内核,而引入设备树(dtb)概念,以设备树文件描述板级信息,驱动通过获取设备树描述信息执行相关过程。此时,驱动工程师编写驱动时则需要实现设备树dtsplatform driver,即是用设备树代替platform device

在这里插入图片描述

linux驱动衍变图

  目前,现在linux主流驱动开发都是采用第三种方式,linux内核较低版本或者历史维护性项目会采用第二种,甚至仍采用第一种的传统方式。对于第二种驱动开发方式,我们一般建立两个源码文件,分别是dev_xxx.cdrv_xxx.cdev_xxx.c用于描述匹配驱动的信息,包括驱动名称(name)、id、内存映射(memory),然后注册当前platform device信息,提供给platform driver匹配(probe);drv_xxx.c则为实际驱动的功能实现,设备驱动的初始化、资源分配(主次设备号、内存空间)、注册、注销以及提供linux标准虚拟文件系统接口(open/read/write/ioctl/mmap)。


实现

  不仅仅是platform驱动,对于包含多个源码文件(.c)的,编译成一个驱动模块文件(.ko)的思路和方法都是类似的,都可以使用该方式。

【1】 各个源码文件的初始化函数和析构函数声明为全局,最终在一个文件调用,并由module_initmodule_exit注册到内核
【2】Makefile将所有目标文件链接为一个文件


  在“Linux 字符驱动之platform框架”文章中的platform字符设备驱动,把dev_mem.cdrv_mem.c分别编译成dev_mem.kodrv_mem.ko模块文件,使用时也需将两个模块文件分别insmod到内核。现修改源码和Makefile将其编译为一个模块文件。

在这里插入图片描述

当前源码目录树

【1】屏蔽dev_mem.c模块初始化和析构函数

module_init(memory_dev_init);
module_exit(memory_dev_exit);
MODULE_LICENSE("GPL");

一个模块只能拥有一个初始化和析构接口,即是一对module_init和module_exit,如果存在多个、接口,会导致编译失败。


【2】增加dev_mem.h头文件,将构造初始化和析构函数声明为全局

extern int __init memory_dev_init(void);
extern void __exit memory_dev_exit(void);

【3】 在drv_mem.c模块初始化和析构函数分别增加上dev_mem.h声明的函数

static int __init memory_drv_init(void)
{
	memory_dev_init();
	return platform_driver_register(&memory_drv);
}

static void __exit memory_drv_exit(void)
{
	memory_dev_exit();
    platform_driver_unregister(&memory_drv);
}

【4】 修改Makefile,把所有编译的目标文件链接成一个可执行文件

ifeq ($(KERNELRELEASE),)

KERNELDIR = /usr/src/linux-headers-4.15.0-91-generic
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *.ko .mod.o *.mod.c *.symvers *.order

else
	obj-m := devmem.o
	devmem-objs = dev_mem.o drv_mem.o
endif

  • obj-m := devmem.o,将代码编译为devmem.ko模块,-m表示编译成模块,-y表示编译到内核

  • devmem-objs = dev_mem.o drv_mem.o,将所有目标文件(dev_mem.o、drv_mem.o)链接为一个执行文件

  假设有更多个源码文件,Makefile文件也是类似的

obj-m := object_name.o
devmem-objs = source0.o source1.o source2.o source3.o

在这里插入图片描述

修改后源码目录树

【5】执行make -j4编译,在当前文件生成指定文件名的驱动模块

在这里插入图片描述

  接下来的加载驱动步骤是相同的,执行sudo insmod devmem.ko即可把dev_memdrv_mem加载到内核。


代码仓库

【1】https://github.com/Prry/linux-drivers/tree/master/devmem_platform

原创文章 128 获赞 147 访问量 36万+

猜你喜欢

转载自blog.csdn.net/qq_20553613/article/details/105264013