嵌入式Linux学习笔记(四)Linux驱动基础

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();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值