i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、
【公众号】迅为电子
【粉丝群】258811263(加群获取驱动文档+例程)
第二部分 Linux内核裁剪与定制
第三十七章 Linux内核模块
本章导读
Linux设备驱动会以内核模块的形式出现,因此,学会编写Linux内核模块编程是学习Linux设备驱动的先决条件。
37.1章节讲解了linux内核模块的概念,并以helloworld为例,将其编译为驱动模块。
37.1 Linux内核模块简介
Linux内核的整体架构本就非常庞大,其包含的组件也非常多。而我们怎样把需要驱动都包含在内
核中呢?
编译驱动有俩种方法
第一种方法:Linux提供了这样的机制,这种机制被称为模块(Module)。把驱动编译成模块,然后使用命令把驱动加载到内核里面。模块本身不被编译入内核映像,从而控制了内核的大小。模块一旦被加载,它就和内核中的其他部分完全一样。
第二种方法:直接把驱动编译到内核中
为了使读者初步建立对模块的感性认识,在第36.3章节我们已经写了一个最简单的驱动helloworld,那么这个章节将来学习怎么将我们写的驱动编译成驱动文件。
我们以i.MX8MM开发板为例,我们编译驱动为内核模块。我们将36.3章节编写的helloworld.c拷贝到Ubuntu的任意路径目录下。
步骤一:
首先使用命令“vim Makefile”创建一个Makefile文件,作者是在/home/topeet/imx8mm/01目录下创建的。Makefile文件内容如下:
obj-m += helloworld.o
KDIR:=/home/topeet/linux/linux-imx
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
- 我们来解释一下makefile的第一行,-m意思是把我们的驱动编译成模块,那么生成的中间文件的名字一般是和驱动C文件同名,这里是helloworld.o
- Makefile的第二行KDIR意思是内核源码的实际路径,注意,大家要根据自己的实际的路径进行修改。作者的源码是放在/home/topeet/linux/linux-imx目录下的
- Makefile第三行PWD?=$(shell pwd)意思是获取当前目录的变量
- Makefile第五行意思是make会进入内核源码的路径,然后把当前路径下的代码编译成模块
- Makefile第七行意思是make clean会清除编译文件
注意:
1 KDIR:=/home/topeet/linux/linux-imx是设备树内核的源码路径,这里使用的是Linux源码包中的内核,请大家根据自己的实际情况进行修改。
2设备树内核源码一定要先编译通过,才能编译驱动,否则会报错。
3 make -C前面的空格是一个tab键
步骤二
设置交叉编译器,请参考本手册“交叉编译器的安装和使用”章节,注意!!! 一定要安装好交叉编译器才可以进行下步操作!!!
为了简化编译步骤,笔者编写了编译脚本build.sh,作者是在/home/topeet/imx8mm/01目录下创建的。此编译脚本在以后的每个实验中要用到,拷贝到驱动文件同级目录即可,以后不在一一赘述,脚本的内容如下所示:
#!/bin/bash
#使用bash来执行此脚本
#clear screen
clear
echo ""
echo -e "\033[32m **** 让我们开始编译驱动程序! **** \033[0m"
echo ""
#set env
. /opt/fsl-imx-xwayland/4.14-sumo/environment-setup-aarch64-poky-linux
export ARCH=arm64
unset LDFLAGS
#clean cache files
make clean
#make
make
#result
#\033[32m set color
#\033[0m clear color
result=$(ls |grep *.ko)
if [ "$result" = "" ];then
echo ""
echo -e "\033[5m\033[31m **** 驱动程序编译失败!报错原因请参考上述提示 ****\033[0m"
echo ""
else
echo ""
echo -e "\033[32m **** 驱动程序编译成功! **** \033[0m"
echo ""
fi
步骤三
我们将36.3章节编写的驱动代码helloworld.c拷贝到和Makefile,build.sh同级目录,如下图所示:
我们使用vscode打开,如下图所示,我们之后的编写代码的工作一律使用vscode。
然后我们输入以下命令,设置文件权限,如下图所示:
chmod 777 -R *
然后运行编译脚本“./build.sh”,编译成功如下图所示:
编译会生生helloworld.ko目标文件,如下图所示:
我们通过nfs将编译好的驱动程序在开发板上加载驱动模块,注意!nfs的配置和使用,请参考本手册“NFS服务器的搭建和使用”章节,此后的章节,我们也是通过nfs的方式往开发板传输文件,以后便不再赘述,大家也可以使用U盘的方式拷贝到开发板,但是为了方便调试,最好使用nfs。
我们进入到共享目录01 ,我们输入命令“insmod helloworld.ko”,可以看到我们编写的helloworld驱动加载成功,如图所示:
我们输入命令“rmmod helloworld”,可以看到我们编写的helloworld驱动拆卸成功,如下图所示
在Linux中,使用lsmod命令可以获得系统中已加载的所有模块以及模块间的依赖关系。