Linux源码目录结构,也就是开发板SDK中kernel目录下的的文件结构,大致分为以下几个部分:
arch:架构相关部分,存放了许多CPU架构,如arm、x86、MIPS等。
block:存放了块设备相关代码,Linux中用block表示块设备,如硬盘、SD卡等。
crypto:存放加密算法目录。
documentation:存放光放Linux内核文档。
drivers:驱动目录,存放了Linux系统支持的硬件驱动源码。
firmware:存放固件目录。
fs:存放支持的文件系统代码,如ext2、ext3、fat等。
include:存放公共的头文件目录。
init:存放Linux内核启动初始化的代码。
ipc:存放进程间通信的代码。
kernel:存放内核本身的代码。
lib:存放库函数的文件夹。
mm:存放内存管理的目录。
net:存放网络相关代码,如TCP/IP协议栈。
scripts:存放脚本文件。
security:存放安全相关代码。
sound:存放音频相关代码。
tools:存放Linux所需的工具文件夹。
usr:存放Linux内核启动的有关代码。
virt:内核虚拟机相关代码。
一个最简单的Linux驱动主要由以下部分组成:
1.头文件
必须包含<linux/module.h>和<linux/init.h>
#include <linux/module.h>
#include <linux/init.h>
2.驱动加载函数
当加载驱动时,驱动加载函数会被内核自动执行
module_init(qudong_init);
3.驱动卸载函数
当卸载驱动时,驱动卸载函数会被内核自动执行
module_exit(qudong_exit);
4.许可证声明
MODULE_LICENSE("GPL");
5.模块参数
模块参数是模块被加载时传递给内核模块的值
6.作者和版本信息
MODULE_AUTHOR("XXX");
MODULE_VERSION("X.X");
编译Linux驱动程序
第一种方法:将驱动放在Linux内核里,然后编译Linux内核
第二种方法:将驱动编译成内核模块,独立于Linux内核之外
内核模块后缀为.ko,可以在系统运行时插入或卸载驱动。
把驱动文件编译内核模块的编译步骤
1.创建格式如下的Makefile
obj-m += helloworld.o
# 表示把目标文件helloworld.o作为模块进行编译。-m表示编译成模块
KDIR:=/path/to/kernel
# 使用绝对路径的方式指定内核源码路径
PWD?=$(shell pwd)
# 获取Makefile文件所在路径
all:
make -C $(KDIR) M=$(PWD) modules
# 进入KDIR目录,使用PWD路径下孕妈和Makefile文件编译驱动模块
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
# 清除编译文件
2.先将开发板的内核源码编译通过
3.设置环境变量
export ARCH=ARM64
export CROSS_COMPILE=/path/to/aarch64-linux-gnu # 设置交叉编译
4.make编译
编译得到的.ko内核模块可以用两个命令加载:
①insmod命令
insmod helloworld.ko
②modprobe命令,用它加载时,这个模块所依赖的模块也会被加载
modprobe helloworld.ko
卸载模块rmmod命令
rmmod helloworld.ko
查看模块信息
①lsmod:列出已载入的内核模块,也可以使用命令cat /proc/modules
②modinfo:查看内核模块信息
modinfo helloworld.ko
make menuconfig图形化配置界面
make menuconfig可以对kernel进行配置,决定是否把某一驱动编译进kernel中。
打开menuconfig步骤:
1.使用命令export ARCH=arm64
2.在kernel源代码的顶层目录下,输入命令make menuconfig
menuconfig界面操作:
1.使用上下左右键移动
2.输入“/”进入搜索模式
3.配置驱动状态
①把驱动配置成模块,用M表示
②把驱动编译到内核里,用*表示
③空白表示不编译
使用空格键切换
4.选项状态由[]、<>、()三种,[]表示有两种状态,<>表示有三种状态,()表示存放字符串和16进制数
与menuconfig有关的几个文件:
1.Kconfig文件
位于kernel目录下的arch/xxx/Kconfig,xxx为开发板架构,这个文件是menuconfig的源文件。
2.config文件和.config文件
config文件位于kernel目录下的arch/xxx/configs下,是开发板出厂默认的配置文件,.config文件位于kernel顶层目录下,与menuconfig中的配置情况相对应,更新menuconfig会对.config更新。
使用命令make xxx_deconfig会根据在arch/xxx/configs目录的默认配置文件生成.config文件。
3.Makefile文件
包含编译规则,决定如何编译Linux内核。
在menuconfig中添加之前没有的驱动支持并添加编译
1.在kernel/drivers的对应文件夹下添加.c格式的驱动文件
2.在同级目录下创建或更改Kconfig文件,增加我们添加的配置选项
3.在上一级drivers目录中的Kconfig文件中将这一级的Kconfig文件包含进去
source "drivers/xxx/Kconfig"
4.在驱动文件的文件夹中创建Makefile文件,将驱动文件和Kconfig文件建立联系,并在上一级的Makefile增加新的驱动
5.在menuconfig中勾选新的驱动保存得到.config文件,用.config文件复制覆盖arch/arm64/configs/xxx_config默认配置文件,再对内核进行编译得到内核的镜像文件
驱动传参
内核支持的驱动传递参数
基本类型:char、bool、int、long、short、byte、ushort、uint
数组:array
字符串:string
参数的读写权限的宏定义在include/linux/stat.h和include/uapi/linux/stat.h下
module_param(name, type, perm);
//name-传递给驱动的变量名,type-参数类型,perm-参数读写权限
module_param_array(name, type, nump, perm);
//name-传递给驱动的变量名,type-参数类型, nump-数组长度, perm-参数读写权限
module_param_string(name, string, len, perm);
//name-传递给驱动的变量名,string-驱动中的变量名,要与name一致, len-字符串大小, perm-参数读写权限
MODULE_PARM_DESC(_parm, desc);
//描述参数信息,_parm-要描述的参数,desc-描述信息
内核符号表
驱动程序可以编译成内核模块.ko文件,每个.ko文件相互独立,在某些场景下内核模块要相互访问,可以利用内核符号表。
“符号”就是内核中的函数名和全局变量名,符号表就是记录它们的文件
实现步骤:
1.在a.c的驱动文件中导出需要的函数或全局变量并编译驱动文件,会生成内核符号表文件Module.symvers
extern xxx();
EXPORT_SYMBOL(xxx); //导出代码
2.将符号表文件Module.symvers拷贝到b.c驱动文件目录下
3.声明并调用函数
extern xxx();