前言
本文主要用来摘录《Linux设备驱动开发详解第四版》一书中学习知识点,本书基于 Linux 4.0 版本,源代码摘录基于 Linux 4.15.18 ,两者之间可能有些出入。
资源链接: 宋宝华《Linux设备驱动开发详解》
一、Linux设备驱动概述及开发环境构建
- 设备驱动的作用
- 无操作系统时的设备驱动
- 有操作系统时的设备驱动
- Linux设备驱动
- Linux设备驱动的开发环境构建
- 设备驱动Hello World:LED驱动
二、驱动设计的硬件基础
- 处理器
- 存储器
- 接口与总线
- CPLD和FPGA
- 原理图分析
- 硬件时序分析
- 芯片数据手册阅读方法
- 仪器仪表使用
三、 Linux内核及内核编程
1、Linux内核的发展与演变
Linux 操作系统是 UNIX 操作系统的一种克隆系统,是一种类 UNIX 操作系统,诞生于1991年10月5日(第一次正式向外公布的时间),起初的作者是 Linus Torvalds。Linux 操作系统的诞生、发展和成长过程依赖着 5 个重要支柱:UNIX 操作系统、Minix 操作系统、GNU 计划、POSIX 标准和 Internet 。
2、Linux 2.6后的内核特点
- 新的调度器
- 内核抢占
- 改进的线程模型
- 虚拟内存的变化
- 文件系统
- 音频
- 总线、设备和驱动模型
- 电源管理
- 联网和IPSec
- 用户界面层
- Linux 3.0后ARM架构的变更
3、Linux内核的组成
(1)Linux内核源代码的目录结构
- arch:包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如 i386、arm、arm64、
powerpc、mips 等。Linux 内核目前已经支持 30 种左右的体系结构。在 arch 目录下,存放的是各个平台以及各个平台的芯片对 Linux 内核进程调度、内存管理、中断等的支持,以及每个具体的 SoC 和电路板的板级支持代码。 - block:块设备驱动程序 I/O 调度。
- crypto:常用加密和散列算法(如 AES、SHA 等),还有一些压缩和 CRC 校验算法。
- documentation:内核各部分的通用解释和注释。
- drivers:设备驱动程序,每个不同的驱动占用一个子目录,如 char、block、net、mtd、i2c 等。
- fs:所支持的各种文件系统,如 EXT、FAT、NTFS、JFFS2 等。
- include:头文件,与系统相关的头文件放置在 include/linux 子目录下。
- init:内核初始化代码。著名的 start_kernel() 就位于 init/main.c 文件中。
- ipc:进程间通信的代码。
- kernel:内核最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放 arch/*/kernel 目录下。
- lib:库文件代码。
- mm:内存管理代码,和平台相关的一部分代码放在 arch/*/mm 目录下。
- net:网络相关代码,实现各种常见的网络协议。
- scripts:用于配置内核的脚本文件。
- security:主要是一个 SELinux 的模块。
- sound:ALSA、OSS 音频设备的驱动核心代码和常用设备驱动。
- usr:实现用于打包和压缩的 cpio 等。
- include:内核API级别头文件。
内核一般要做到 drivers 与 arch 的软件架构分离,驱动中不包含板级信息,让驱动跨平台。同时内核的通用部分(如 kernel、fs、ipc、net 等)则与具体的硬件( arch 和 drivers )剥离。
(2)Linux内核的组成部分
Linux 内核主要由进程调度(SCHED)、内存管理(MM)、虚拟文件系统(VFS)、
网络接口(NET)和进程间通信(IPC)5 个子系统组成。
① 进程调度
② 内存管理
③ 虚拟文件系统
Linux 虚拟文件系统隐藏了各种硬件的具体细节,为所有设备提供了统一的接口。而且,它独立于各个具体的文件系统,是对各种文件系统的一个抽象。它为上层的应用程序提供了统一的 vfs_read() 、vfs_write() 等接口,并调用具体底层文件系统或者设备驱动中实现的 file_operations 结构体的成员函数。
④ 网络接口
网络接口提供了对各种网络标准的存取和各种网络硬件的支持。
⑤ 进程间通信
Linux 支持进程间的多种通信机制,包含信号量、共享内存、消息队列、管道、UNIX 域套接字等,这些机制可协助多个进程、多资源的互斥访问、进程间的同步和消息传递。在实际的 Linux 应用中,人们更多地趋向于使用 UNIX 域套接字,而不是 System V IPC 中的消息队列等机制。Android 内核则新增了 Binder 进程间通信方式。
Linux 内核 5 个组成部分之间的依赖关系如下。
进程调度与内存管理之间的关系:这两个子系统互相依赖。在多程序环境下,程序要运行,则必须为之创建进程,而创建进程的第一件事情,就是将程序和数据装入内存。
进程间通信与内存管理的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制,这种机制允许两个进程除了拥有自己的私有空间之外,还可以存取共同的内存区域。
虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS),也利用内存管理支持 RAMDISK 设备。
内存管理与虚拟文件系统之间的关系:内存管理利用虚拟文件系统支持交换,交换进程定期由调度程序调度,这也是内存管理依赖于进程调度的原因。当一个进程存取的内存映射被换出时,内存管理向虚拟文件系统发出请求,同时,挂起当前正在运行的进程。
除了这些依赖关系外,内核中的所有子系统还要依赖于一些共同的资源。这些资源包括所有子系统都用到的 API ,如分配和释放内存空间的函数、输出警告或错误消息的函数及系统提供的调试接口等。
(3)Linux内核空间与用户空间
ARM Linux 的系统调用实现原理是采用 swi 软中断从用户(usr)模式陷入管理模式(svc)。
4、Linux内核的编译及加载
(1)Linux内核的编译
make config #(基于文本的最为传统的配置界面,不推荐使用) make menuconfig #(基于文本菜单的配置界面) make xconfig #(要求QT被安装) make gconfig #(要求GTK+被安装)
内核配置包含的条目相当多,arch/arm/configs/xxx_defconfig 文件包含了许多电路板的默认配置。只需要运行 make ARCH=arm xxx_defconfig 就可以为 xxx 开发板配置内核。
编译内核和模块的方法是:
make ARCH=arm xxx_defconfig # 使用默认配置 make ARCH=arm zImage make ARCH=arm modules
上述命令中,如果 ARCH=arm 已经作为环境变量导出,则不再需要在 make 命令后书写该选项。执行完上述命令后,在源代码的根目录下会得到未压缩的内核映像 vmlinux 和内核符号表文件 System.map ,在 arch/arm/boot/ 目录下会得到压缩的内核映像 zImage,在内核各对应目录内得到选中的内核模块。
(2)Kconfig 和 Makefile
在 Linux 内核中增加程序需要完成以下 3 项工作。
- 将编写的源代码复制到 Linux 内核源代码的相应目录中。
- 在目录的 Kconfig 文件中增加关于新源代码对应项目的编译配置选项。
- 在目录的 Makefile 文件中增加对新源代码的编译条目。
(3)Linux内核的引导
Linux设备驱动开发详解2:https://developer.aliyun.com/article/1597417