在学习编程的旅程中,无论是初涉 C 语言还是探索其他编程语言,我们往往以一句经典的 “Hello, World!” 作为起点,以此叩开代码世界的大门。这一简单而富有仪式感的传统,不仅象征着程序员与计算机之间的第一次对话,更承载了无数开发者对技术的热爱与追求。同样地,在驱动程序编程的领域,我们也可以延续这一传统,以 “Hello, World!” 作为我们的首个驱动程序,开启通往底层系统开发的奇妙之旅。
接下来,我们将着手编写第一个驱动程序——一个名为 “Hello, World!” 的简单驱动模块。这不仅是我们迈向驱动开发的第一步,更是理解 Linux 内核机制的重要起点。通过这段代码,我们将初步领略驱动程序的基本结构、加载与卸载流程,以及与内核交互的方式。准备好了吗?让我们一起开始这段充满挑战与乐趣的驱动开发之旅吧!
一、驱动源码
实验准备
- 建议代码存放目录:
kernel/drivers/test/ - 运行命令创建文件:
touch hello.c - 实验代码:《
01_helloworld》
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void) // 驱动入口函数
{
printk("helloworld_init\r\n");//注意: 内核打印用 printk 而不是 printf
return 0;
}
static void __exit helloworld_exit(void) // 驱动出口函数
{
printk("helloworld_exit\r\n");
}
module_init(helloworld_init); // 告诉 linux 模块入口函数,加载模块代码到操作系统
module_exit(helloworld_exit); // 卸载
MODULE_LICENSE("GPL v2"); // 同意 GPL 开源协议
MODULE_VERSION("1.0"); // 驱动的版本
MODULE_DESCRIPTION("helloworld Driver"); // lsmod2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
配套 Makefile:
export ARCH=arm64
export CROSS_COMPILE=/home/book/rk/tspi/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
obj-m += hello.o # 此处要和你的驱动源文件同名
KDIR := /home/book/rk/tspi/kernel # 这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules # make 操作
clean:
make -C $(KDIR) M=$(PWD) clean # make clean 操作2
3
4
5
6
7
8
9
注意
CROSS_COMPILE 以自己的 SDK 路径为准,上图中我的 SDK 源码放在 /home/book/rk/tspi 目录。
这段看似简洁的 helloworld 驱动代码,实则蕴藏着驱动开发的核心框架与逻辑。尽管其外表简单,但内在却包含了驱动开发所需的基本要素。接下来,我们将深入探讨这些构成部分。
adb push E:\tspi\hello.ko /mnt/hello.ko
insmod /mnt/hello.ko2
二、驱动的基本框架
Linux 驱动的基本框架主要包含以下核心部分:
必须包含的组件:
- 加载函数:驱动模块被加载到内核时,这个函数会自动运行,负责初始化设备(比如分配资源、配置硬件)。
- 卸载函数:当移除驱动模块时,这个函数会执行收尾工作(比如释放资源、关闭设备)。
- 许可证声明:必须标明模块使用的许可协议(如 GPL),否则系统会警告“内核被污染”,表示模块来源不可信。
可选但常用的组件:
- 模块参数:允许用户在加载驱动时,通过命令行传递配置值(例如设置设备名称或调试级别)。
- 导出符号:如果需要让其他驱动调用本模块的函数或变量,就要“导出”这些接口。
- 作者信息:注明开发者联系方式或模块用途,方便后续维护或问题反馈。
简单来说,核心就是“加载时初始化、退出时清理、必须声明许可证”,其他功能根据需求添加。比如调试时用参数调整设置,多个驱动协作时用导出符号共享功能,作者信息则像软件的版权声明一样起说明作用。
三、实验
源代码下载
git clone git@gitee.com:yangxuesong314/linux-driver.git- 若之前已 git 拉取代码可以忽略
- 代码位于:
linux-driver/01.Linux模块化编程/01.helloworld驱动实验
1、第一步
进入 ~/LubanCat_SDK/kernel/drivers 目录,编辑 Makefile 文件。
cd kernel/drivers
vim Makefile2

2、第二步
创建必要的文件。
touch hello.c
touch Makefile2
3、第三步
hello.c 源文件编程:
vim hello.c#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void) // 驱动入口函数
{
printk("helloworld_init\r\n");//注意: 内核打印用 printk 而不是 printf
return 0;
}
static void __exit helloworld_exit(void) // 驱动出口函数
{
printk("helloworld_exit\r\n");
}
module_init(helloworld_init); // 告诉 linux 模块入口函数,加载模块代码到操作系统
module_exit(helloworld_exit); // 卸载
MODULE_LICENSE("GPL v2"); // 同意 GPL 开源协议
MODULE_VERSION("1.0"); // 驱动的版本
MODULE_AUTHOR("linux");
MODULE_DESCRIPTION("helloworld Driver"); // lsmod2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Makefile 源文件编程:
vim Makefileexport ARCH=arm64
export CROSS_COMPILE=/home/book/rk/tspi/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
obj-m += hello.o # 此处要和你的驱动源文件同名
KDIR := /home/book/rk/tspi/kernel # 这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules # make 操作
clean:
make -C $(KDIR) M=$(PWD) clean # make clean 操作2
3
4
5
6
7
8
9
四、Makefile 详细说明
Makefile 是构建驱动程序的重要工具,它定义了如何编译和链接源文件。以下是一些关键点:
- 架构(ARCH):指定目标架构,如 ARM 或 ARM64。
- 交叉编译链(CROSS_COMPILE):设置为
aarch64-linux-gnu-。 - 编译对象(obj-m):
m表示编译成.ko模块。y表示直接编译进内核。
- 内核源码路径(KDIR):指向内核源码的根目录。
- 当前路径(PWD):通过
$(shell pwd)动态获取。 - 编译命令:
make -C $(KDIR) M=$(PWD) modules - 清除命令:
make -C $(KDIR) M=$(PWD) clean
五、实验操作
以下步骤完成驱动的编译与加载:
- 清理旧的编译结果:
make clean - 编译驱动:
make - 将生成的
.ko文件推送到设备:adb push hell.ko /mnt - 设置文件权限:
chmod 777 /mnt/hell.ko - 加载模块:
insmod hell.ko - 查看已加载模块:
lsmod - 查看日志输出效果:
dmesg
