目录
[一、驱动开发必备 C 语言核心:只讲必用的,不搞无用内卷](#一、驱动开发必备 C 语言核心:只讲必用的,不搞无用内卷)
[1. 指针:驱动的灵魂,绕不开的核心](#1. 指针:驱动的灵魂,绕不开的核心)
[驱动里必用的指针用法,你只需要掌握这 4 个:](#驱动里必用的指针用法,你只需要掌握这 4 个:)
[2. 结构体:驱动里的 "数据容器"](#2. 结构体:驱动里的 “数据容器”)
[3. Linux 文件 IO:驱动的核心操作接口](#3. Linux 文件 IO:驱动的核心操作接口)
[4. 内核内存管理:驱动里的内存分配](#4. 内核内存管理:驱动里的内存分配)
[二、Linux 核心基础:不用背,会用这些就够了](#二、Linux 核心基础:不用背,会用这些就够了)
[1. 驱动开发必备 Linux 命令,按用途分类给你整理好了](#1. 驱动开发必备 Linux 命令,按用途分类给你整理好了)
[(4)日志查看与调试命令(驱动调试的核心,找 bug 全靠它)](#(4)日志查看与调试命令(驱动调试的核心,找 bug 全靠它))
[2. Linux 核心概念,必须懂的底层逻辑](#2. Linux 核心概念,必须懂的底层逻辑)
[(1)Linux 目录结构,重点记这几个和驱动相关的目录](#(1)Linux 目录结构,重点记这几个和驱动相关的目录)
[四、瑞芯微 SDK 全貌:拿到 SDK 再也不懵了](#四、瑞芯微 SDK 全貌:拿到 SDK 再也不懵了)
[先讲:SDK 是什么?从哪里来?](#先讲:SDK 是什么?从哪里来?)
[RK SDK 核心目录结构,重点标红给你](#RK SDK 核心目录结构,重点标红给你)
[小白必记的 4 个核心目录,90% 的开发工作都在这里:](#小白必记的 4 个核心目录,90% 的开发工作都在这里:)
[1. 必备软件清单,全是免费好用的](#1. 必备软件清单,全是免费好用的)
[2. 学习资料渠道,全是新手友好的](#2. 学习资料渠道,全是新手友好的)
【本文首发于 CSDN,作者:黒漂技术佬,未经授权禁止转载】
大家好,我是黒漂技术佬。上一篇扫盲文发出去之后,后台又炸了,小白兄弟们统一反馈:
"佬,我看懂了要学啥,但是我 C 语言忘光了,Linux 命令也只会个 ls cd,有没有一篇能把所有前置知识补全的?不用我到处找资料的那种"
安排!这篇文章,就是专门给零基础小白准备的前置知识急救包 。我不会给你讲大学课本里那些没用的理论,只讲 RK 安卓驱动开发里必用、高频、绕不开的知识点,零基础也能看懂,学完这篇,后面的环境搭建、驱动实战,你就能完全跟上,不会再出现 "每个字都认识,连起来看不懂" 的情况。
废话不多说,直接上干货。
一、驱动开发必备 C 语言核心:只讲必用的,不搞无用内卷
C 语言是驱动开发的母语,安卓驱动的内核部分,100% 都是用 C 语言写的。很多小白说 "我 C 语言没学好,能不能学驱动?",别慌,你不用把 C 语言学到精通,只需要把下面这几个核心知识点吃透,就足够入门驱动开发了。
1. 指针:驱动的灵魂,绕不开的核心
指针是 C 语言的灵魂,也是驱动里用的最多的语法,没有之一。很多小白觉得指针难,其实用大白话讲,指针就两个核心:指针,就是一个存储内存地址的变量,它指向的是一块内存的位置,而不是内存里存的数据。
举个通俗的例子:你把一个快递(数据)放在了快递柜的 3 号柜(内存地址),指针就是一张写着 "3 号柜" 的纸条,它本身不是快递,但是你通过这张纸条,就能找到快递柜里的快递,还能修改里面的东西。
驱动里必用的指针用法,你只需要掌握这 4 个:
-
普通指针与取地址、解引用
c
运行
int a = 10; // 定义一个int变量a,存在内存里 int *p = &a; // 定义一个int类型的指针p,&a是取a的内存地址,p指向a的地址 *p = 20; // 解引用,通过指针p修改它指向的内存里的数据,也就是把a改成20小白避坑:
int *p里的*是用来定义指针的,*p里的*是用来解引用的,别搞混。 -
结构体指针 驱动里到处都是结构体,比如内核里的
file_operations、cdev,全是结构体,而操作结构体,90% 都是用结构体指针。c
运行
// 定义一个驱动里常用的设备结构体 struct led_dev { int gpio_num; // LED对应的GPIO编号 char dev_name[20]; // 设备名称 }; struct led_dev led; // 定义一个结构体变量 struct led_dev *p_led = &led; // 定义结构体指针,指向led的地址 // 结构体指针用->访问成员,结构体变量用.访问成员 p_led->gpio_num = 10; // 等价于 led.gpio_num = 10;小白必记:结构体指针用
->访问成员,结构体变量用.访问成员,驱动里 90% 的场景都是用结构体指针。 -
函数指针 驱动的核心,就是用函数指针把我们写的驱动函数,注册到内核里。比如字符设备驱动里的
file_operations结构体,里面全是函数指针,你必须懂。c
运行
// 定义一个函数,对应驱动里的open操作 int led_open(struct inode *inode, struct file *filp) { printk("LED设备被打开了\n"); return 0; } // 定义file_operations结构体,用函数指针把led_open绑定到open成员 static const struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, // 函数指针赋值,把我们写的led_open函数,绑定到open操作 };大白话讲:函数指针,就是把一个函数的入口地址,赋值给结构体里的成员,当内核要执行 open 操作的时候,就会自动调用我们写的 led_open 函数。这就是字符设备驱动的核心机制,必须懂。
-
空指针与野指针避坑这是新手写驱动最容易导致内核崩溃的问题:
- 空指针:指针指向
NULL(0 地址),对空指针解引用,内核直接 panic 崩溃; - 野指针:指针指向的内存是随机的、未申请的,对野指针操作,会直接修改内核的随机内存,导致系统崩溃、数据错乱。小白红线:使用指针前,必须先给它赋值合法的内存地址,绝对不能对未初始化的指针进行操作。
- 空指针:指针指向
2. 结构体:驱动里的 "数据容器"
结构体,就是把多个不同类型的变量,打包成一个整体,方便管理。驱动里,我们会把一个设备的所有信息(GPIO 编号、设备名称、设备号、私有数据等),都打包在一个结构体里,这是驱动开发的标准写法。
你只需要掌握结构体的定义、初始化、结构体指针的用法,就足够了,上面讲结构体指针的时候已经给了例子,这里就不重复了。
3. Linux 文件 IO:驱动的核心操作接口
Linux 里有一个核心思想:一切皆文件 。所有的硬件设备,在 Linux 里都会被抽象成一个文件,放在/dev目录下,比如 LED 设备,就是/dev/led。
我们对硬件设备的所有操作(打开、读、写、控制),本质上都是对这个设备文件的操作。而驱动里的核心函数,就是和这些文件 IO 操作一一对应的:
表格
| 用户空间文件 IO 函数 | 驱动里对应的函数指针 | 作用 |
|---|---|---|
| open() | .open | 打开设备文件,初始化设备 |
| read() | .read | 从设备里读取数据(比如读取传感器数据) |
| write() | .write | 向设备里写数据(比如控制 LED 亮灭) |
| ioctl() | .unlocked_ioctl | 对设备进行自定义控制(比如设置 PWM 频率) |
| close() | .release | 关闭设备文件,释放资源 |
这就是字符设备驱动的核心框架,你把这个对应关系搞懂了,后面写驱动就会豁然开朗。
4. 内核内存管理:驱动里的内存分配
驱动运行在内核空间,和用户空间的内存管理完全不一样,你不能用用户空间的malloc()和free(),必须用内核提供的内存分配函数,入门阶段你只需要掌握两个:
kmalloc():分配连续的物理内存,用于小内存分配,驱动里最常用,对应释放函数kfree();vmalloc():分配非连续的虚拟内存,用于大内存分配,对应释放函数vfree()。
小白避坑:内核空间的内存资源极其宝贵,分配的内存用完必须释放,绝对不能出现内存泄漏,不然会导致系统崩溃。
二、Linux 核心基础:不用背,会用这些就够了
很多小白一听到 Linux 就头大,觉得要背几百个命令,其实完全不用。驱动开发入门阶段,你只需要掌握下面这些必备的命令和核心概念,就足够了,不用背,用多了自然就记住了。
1. 驱动开发必备 Linux 命令,按用途分类给你整理好了
(1)文件操作命令(最常用,每天都要用)
表格
| 命令 | 作用 | 驱动开发里的高频场景 |
|---|---|---|
| ls | 查看目录下的文件 | 查看驱动目录、编译生成的文件 |
| cd | 切换目录 | 进入内核源码目录、驱动目录 |
| mkdir | 创建目录 | 创建自己的驱动目录 |
| cp | 复制文件 / 目录 | 复制驱动源码、镜像文件 |
| mv | 移动 / 重命名文件 | 重命名驱动文件、移动编译产物 |
| rm | 删除文件 / 目录 | 删除编译生成的临时文件,rm -rf慎用! |
| cat | 查看文件内容 | 查看设备树文件、驱动源码、内核日志 |
| touch | 创建空文件 | 创建驱动的.c 文件、Makefile 文件 |
(2)权限管理命令(驱动必用,不然设备访问不了)
Linux 里所有的文件都有权限限制,设备文件也一样,如果你不给设备文件设置读写权限,安卓 App 根本访问不了,这两个命令必须会:
chmod:修改文件权限,最常用的是chmod 777 /dev/led,给 led 设备文件全开权限(入门测试用,量产要注意权限安全);chown:修改文件所属用户 / 用户组,用于修改设备文件的所属者,让安卓系统能访问。
(3)编译相关命令(编译驱动、内核必用)
gcc:C 语言编译器,编译测试程序必用;make:执行 Makefile 编译脚本,编译内核、驱动全靠它,最常用的是make -j8,用 8 线程编译,速度更快;make clean:清除之前的编译产物,重新编译的时候必用。
(4)日志查看与调试命令(驱动调试的核心,找 bug 全靠它)
dmesg:查看内核打印日志,驱动里用printk()打印的调试信息,全用这个命令看,驱动调试必用!高频用法:dmesg | grep led,过滤只看和 led 相关的日志;cat /proc/kmsg:实时查看内核日志,和 dmesg 配合使用;lsmod:查看当前内核加载的驱动模块;insmod:加载驱动模块,比如insmod led_drv.ko;rmmod:卸载驱动模块,比如rmmod led_drv;mknod:创建设备文件,手动创建设备节点的时候用。
(5)文本编辑命令(改代码、改配置必用)
vi/vim:Linux 里最常用的文本编辑器,入门阶段你只需要掌握这几个操作就够了:vim led_drv.c:打开 / 创建文件;- 按
i进入编辑模式,就能写代码了; - 按
ESC退出编辑模式,输入:wq保存并退出,输入:q!强制退出不保存。
别去学那些花里胡哨的 vim 操作,入门阶段能改代码、保存退出就够了,等你熟练了再慢慢学进阶操作。
2. Linux 核心概念,必须懂的底层逻辑
(1)Linux 目录结构,重点记这几个和驱动相关的目录
Linux 的目录结构是树形的,根目录是/,所有的文件都在根目录下面,入门阶段你只需要记住这几个核心目录:
/dev:设备文件目录,所有的硬件设备文件都在这里,我们写的驱动设备,也会在这里生成对应的文件,比如/dev/led;/proc:虚拟文件系统,用于查看内核状态、进程信息、驱动信息,比如/proc/devices可以查看当前系统注册的设备号;/sys:虚拟文件系统,和设备树、驱动模型强相关,驱动调试的时候经常用;/home:用户目录,我们的开发环境、SDK、源码,一般都放在这里;/lib:库文件目录,存放内核模块、共享库文件。
(2)内核态与用户态,最核心的边界
这是 Linux 最核心的概念,也是小白必须懂的:Linux 系统把内存分成了两个空间:内核态 和用户态。
- 用户态:应用程序运行的空间,权限很低,不能直接操作硬件、不能直接访问内核内存,所有的操作都要通过内核提供的系统调用完成;
- 内核态:Linux 内核、驱动运行的空间,拥有最高权限,可以直接操作硬件、访问所有内存、管理整个系统的资源。
我们写的驱动,就是运行在内核态的,而安卓 App 是运行在用户态的,两者不能直接互相访问内存,必须通过内核提供的copy_from_user()和copy_to_user()函数,完成用户空间和内核空间的数据交互,这是驱动开发里的核心操作,后面实战会详细讲。
小白红线:内核态里绝对不能做的事 ------ 不能用用户态的malloc()、printf()等函数,不能在中断上下文里睡眠,不能访问用户空间的内存,不然内核直接崩溃。
三、安卓系统基础:重点搞懂和驱动相关的分层架构
上一篇扫盲文里,我已经给大家讲了安卓的分层架构,这里再给大家深入讲一下和驱动开发强相关的部分,让你彻底搞懂,我们写的驱动,是怎么和安卓系统联动的。
安卓系统四层架构,重点关注和驱动相关的两层
安卓系统从上到下,分为四层,我们做驱动开发,重点关注下面两层,上面两层只需要懂基本的交互逻辑就行:
- 应用层(App 层):用户能看到的所有安卓 App,都在这一层,比如我们写的控制 LED 的 App,运行在用户态,权限最低,不能直接操作驱动;
- 框架层(Framework 层) :安卓系统提供的 Java API 集合,比如
CameraManager、InputManager,App 通过调用这些 API,实现和系统的交互。Framework 层运行在用户态,通过 JNI 接口,调用底层的 HAL 层代码; - 硬件抽象层(HAL 层):重点中的重点!这是连接 Framework 层和内核驱动的桥梁,用 C/C++ 编写,运行在用户态。它定义了一套标准的接口,Framework 层只需要调用这套标准接口,不用关心底层驱动是怎么实现的;而硬件厂商只需要按照这套接口,实现自己的硬件逻辑,就能适配安卓系统。
- Linux 内核层:我们写的驱动就在这一层,运行在内核态,拥有最高权限,直接操作硬件,向上给 HAL 层提供设备文件操作接口。
再讲一遍:安卓驱动的完整数据流转路径
以 "App 点击按钮,控制 LED 亮灭" 为例,给你讲清楚每一步的流转,彻底打通你的任督二脉:
- 安卓 App 里,用户点击 "开灯" 按钮,App 调用 Framework 层提供的自定义 API;
- Framework 层的 Java API,通过 JNI 接口,调用 HAL 层里的 C/C++ 函数;
- HAL 层的函数,通过文件 IO 接口(open/write),打开
/dev/led设备文件,向内核驱动发送 "开灯" 的指令; - 内核驱动接收到 HAL 层的指令,操作对应的 GPIO 口,输出高电平,点亮 LED 灯;
- 关灯的流程,完全反过来,一模一样。
你看,整个流程里,内核驱动只是其中的一环,HAL 层是连接上层和底层的核心桥梁,这就是为什么我一直强调,安卓驱动开发必须打通全链路,只写内核驱动,App 根本用不了。
四、瑞芯微 SDK 全貌:拿到 SDK 再也不懵了
很多小白拿到瑞芯微的 SDK,一看几百个目录,直接懵了,根本不知道哪个目录是干嘛的,该去哪里写驱动。今天我给你把 RK SDK 的目录结构扒得明明白白,告诉你哪些是重点目录,哪些入门阶段根本不用碰。
先讲:SDK 是什么?从哪里来?
SDK(Software Development Kit,软件开发工具包),就是瑞芯微官方给我们提供的,包含了完整的安卓源码、Linux 内核源码、U-Boot 源码、驱动源码、编译工具、板级配置文件的完整开发包。我们做 RK 平台的安卓驱动开发,所有的工作,都是在这个 SDK 里完成的。
SDK 获取渠道:
- 首选:你买的开发板的厂商,会给你提供适配好对应开发板的 SDK,不用自己从零适配,新手直接用这个,省 90% 的事;
- 官方渠道:瑞芯微开发者社区,需要企业资质申请,个人新手很难拿到,不用纠结。
RK SDK 核心目录结构,重点标红给你
我以 RK3568 的安卓 11 SDK 为例,给你讲核心目录,入门阶段,你只需要关注我标红的 4 个目录就行,其他的不用碰,别瞎改,改坏了编译不过:
plaintext
RK3568_Android11_SDK/
├── u-boot/ # U-Boot源码,系统启动的第一阶段,入门阶段不用改,知道是干嘛的就行
├── kernel/ # 【重点中的重点】Linux内核源码,我们的驱动代码、设备树,全在这里面
│ ├── drivers/ # 内核驱动目录,我们写的驱动代码,就放在这个目录对应的子目录里
│ └── arch/arm64/boot/dts/rockchip/ # 【重点】RK平台设备树目录,板级设备树全在这里
├── hardware/ # 【重点】安卓HAL层源码,我们写的HAL层代码,就在这里面
│ └── rockchip/ # RK官方提供的HAL层适配代码,我们自己的HAL层代码也放在这里
├── device/ # 【重点】板级配置文件,开发板对应的分区配置、编译配置、硬件适配配置
├── out/ # 编译输出目录,编译好的镜像文件、固件,全在这里面
├── build/ # 安卓编译脚本,入门阶段不用改
├── external/ # 安卓第三方开源库,入门阶段不用改
├── frameworks/ # 安卓Framework层源码,进阶阶段再碰,入门不用改
└── system/ # 安卓系统核心库,入门阶段不用改
小白必记的 4 个核心目录,90% 的开发工作都在这里:
- kernel 目录 :内核源码目录,我们写的 Linux 内核驱动,全放在
kernel/drivers/对应的子目录里,比如 GPIO 驱动放在drivers/gpio/,LED 驱动放在drivers/leds/,字符设备驱动可以自己建个drivers/char/xxx目录。设备树文件全在kernel/arch/arm64/boot/dts/rockchip/目录里,我们修改设备树,就是改这个目录里的 dts/dtsi 文件。 - hardware 目录:HAL 层源码目录,我们写的安卓 HAL 层代码,全在这里面,实现和内核驱动的交互,给 Framework 层提供接口。
- device 目录:板级配置目录,开发板对应的编译配置、分区配置、屏幕适配配置,都在这里面,入门阶段只需要看懂,不用大改。
- out 目录:编译输出目录,我们编译好的内核镜像、boot.img、system.img、完整的烧录固件,全在这里面,烧录的时候就是从这个目录里拿镜像。
五、小白学习工具包:必备软件、资料渠道全汇总
最后,给大家整理了入门阶段必备的工具和资料渠道,不用你到处找,直接照着用就行。
1. 必备软件清单,全是免费好用的
表格
| 软件名称 | 作用 | 下载渠道 |
|---|---|---|
| VMware Workstation Player | 虚拟机软件,用来装 Ubuntu 开发环境,免费版足够用 | VMware 官网 |
| Ubuntu 20.04 LTS | 开发环境系统,强烈推荐用 20.04 版本,别用 22.04 以上的,兼容性差,很多 SDK 编译不过 | Ubuntu 官网 |
| MobaXterm | 串口调试、SSH 连接神器,集成了串口、SSH、FTP 等功能,比 SecureCRT 好用,免费版足够 | MobaXterm 官网 |
| RKDevTool | 瑞芯微官方烧录工具,用来给开发板烧录固件,免费 | 瑞芯微开发者社区、开发板厂商资料 |
| DriverAssitant | 瑞芯微 USB 驱动,烧录的时候必须装,不然电脑识别不到开发板 | 同上 |
| VS Code | 代码编辑器,看内核源码、写驱动代码神器,比 Source Insight 轻量,免费 | VS Code 官网 |
| Notepad++ | 文本编辑器,看配置文件、改设备树超好用,免费 | Notepad++ 官网 |
2. 学习资料渠道,全是新手友好的
- 开发板厂商配套资料:野火、正点原子、韦东山的 RK3568 开发板,都有配套的用户手册、教程、源码,新手入门首选,比网上零散的教程靠谱得多;
- 瑞芯微开发者社区:官方文档、SDK、芯片手册的唯一官方渠道,进阶必看;
- CSDN:国内最大的嵌入式技术社区,遇到问题直接搜,90% 的坑都有人踩过,有解决方案;
- Linux 内核官方文档:内核驱动开发的权威文档,进阶必看;
- 安卓官方开发者文档:安卓 HAL 层、Framework 层的权威文档,进阶必看。
结尾说两句
这篇文章,把 RK 安卓驱动开发必备的所有前置知识,全给你补全了。不用你再到处找资料,把这篇文章里的知识点吃透,你就已经超过了 80% 刚入门的小白,后面的环境搭建、驱动实战,你就能完全跟上。
下一篇,我们正式进入实操环节,保姆级手把手带你搭建 RK 安卓驱动开发环境,从 Ubuntu 虚拟机安装、依赖库配置,到 SDK 编译、镜像烧录,一步不落,所有报错都给你解决方案,保证你一次搭建成功,不踩坑。
我是黒漂技术佬,关注我,带你零基础入门 RK 安卓驱动开发,不迷路。有任何知识点不懂的,评论区留言,我都会一一回复。