一、 总体流程图 (Workflow)

1.源码编写 

 2.环境配置 

 3.内核/驱动编译 

 4.文件传输 

 5.上机验证


二、 详细步骤与实现 (How)

1. 环境配置 (Configuration)

在 Ubuntu 主机中,必须告知编译器目标架构和交叉编译器路径。

codeBash

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# 确保内核源码路径正确
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88

2. 内核编译 (如果涉及内核/设备树更新)

如果你的驱动依赖新的内核特性或修改了硬件引脚(设备树),需要执行:

codeBash

make 100ask_imx6ull_defconfig  # 配置
make zImage -j4                # 编译内核
make dtbs                      # 编译设备树

3. 驱动程序编译

编写 Makefile 并执行 make:

  • 实现: make -C /home/book/linux-4.9.88 M=/home/book/drv_projects/hello_drv modules
    
    产物: hello_drv.ko

4. 传输与加载

使用 ADB 或 NFS 将文件推送到开发板:

codeBash

# Ubuntu 执行
adb push hello_drv.ko /root/

# 开发板执行
insmod hello_drv.ko

三、 为什么要这么做?(Why - 核心原理)

配置/步骤 为什么需要这么做?
配置 ARCH/CROSS_COMPILE 交叉编译需求。开发是在 X86 架构的电脑上,但程序运行在 ARM 架构的开发板上。必须使用特定的编译器,否则程序无法在板子上运行。
指定 KERN_DIR 依赖对齐。驱动程序不是孤立的,它需要包含内核的头文件。如果驱动编译时参考的内核源码版本与开发板运行的内核版本不一致,会导致无法加载(版本校验失败)。
配置设备树 (.dts) 解耦硬件。IMX6ULL 有数百个引脚,内核不知道哪个引脚接了你的设备。设备树描述了硬件资源,让同一个内核镜像能适配不同的电路板。
使用 insmod 加载 动态扩展。Linux 是宏内核,但支持模块化。不需要为了加一个驱动就重启整个系统或重新烧写系统,提高了开发效率。

四、 实现过程 

驱动代码核心结构:

  1. 入口函数 (init):调用 register_chrdev 注册驱动,device_create 创建设备节点。

  2. 出口函数 (exit):调用 unregister_chrdev 注销驱动,释放资源。

  3. 操作函数集 (file_operations):实现 .open, .read, .write 等,对应用户空间的系统调用。

  4. 协议说明:MODULE_LICENSE("GPL")。

应用层测试逻辑:

  • 调用 fd = open("/dev/hello", O_RDWR) 打开驱动文件。

  • 调用 write(fd, buf, len) 或 read(fd, buf, len) 与内核通信。


五、 实验现象 

当你按照步骤完成操作后,应该观察到以下现象:

1. 加载阶段

  • 执行: insmod hello_drv.ko

  • 现象:

    • 终端可能弹出内核打印信息(由 printk 产生)。

    • 执行 lsmod:能看到 hello_drv 模块。

    • 执行 ls /dev/hello:必须能看到这个文件,这代表驱动成功在系统中“落户”。

    • 执行 cat /proc/devices:能看到 hello 及其对应的主设备号。

2. 测试阶段

  • 执行: ./hello_drv_test -w "100ask"

  • 现象:

    • 应用层:提示发送成功。

    • 内核层(执行 dmesg | tail):看到内核打印出 hello_drv_write: get data: 100ask。

3. 卸载阶段

  • 执行: rmmod hello_drv

  • 现象:

    • 执行 lsmod:模块消失。

    • 执行 ls /dev/hello:设备节点自动消失(代表驱动资源已清理干净)。


六、 常见问题复盘

  1. Unknown symbol in module:通常是因为驱动依赖的其他模块没加载,或者内核源码没有预先编译。

  2. Exec format error:交叉编译器用错了(编译成了 X86 格式),或者 ARCH 没设为 arm。

  3. File exists:说明驱动已经加载过了,需要先 rmmod。


学习心得 

驱动开发的核心在于: 把硬件当作“文件”来处理。
内核编译的关键在于: 源码版本与运行版本必须高度匹配。
实验成功的标志在于: 用户空间的 write 能在内核空间产生 printk 响应。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐