【从零开始撸内核驱动源码】:以ttyserial(串口驱动)为例,串联字符设备驱动基础知识点的学习计划
本文约1800字,今年没有回老家,年到今日也差不多过完了,极其放松和休闲的一个年,身心完全的放松了。今日开始逐步进入学习状态,之前正式驱动走读的帖子《【从零开始撸内核驱动源码】:ttynull驱动》 算是入门开始撸驱动源码了,接下来的计划是一步一步将字符设备驱动的基础知识点梳理完毕,看书厘清理论知识,实操出真知,强化知识点。本文整理出字符设备驱动的走读路线。
关注公众号, 即可获得与Linux相关的电子书籍以及常用开发工具,文末有文档清单。
ttynull 是纯软件模拟的空设备,而 ttyserial(串口驱动)是tty子系统中最经典、最基础的有实际硬件交互的驱动,完美衔接之前的学习进度, 我粗略ttyserial目录内容, 整理出如下学习计划:
第一步:先吃透tty子系统的“极简硬件驱动”—— tyserial
代码路径:drivers/tty/serial/8250
优先看最简化的串口驱动:8250_core.c(8250 是最经典的 UART 芯片,Linux 串口驱动的基石),先跳过复杂的平台适配,聚焦 8250_port.c 中 “端口初始化、数据收发、中断处理” 的核心逻辑。
8250_port.c是8250系列 UART(通用异步收发器)串口驱动的端口操作核心层,是连接上层 TTY 子系统与底层硬件 UART 的关键桥梁。核心作用是屏蔽不同型号 UART 硬件的差异,为上层提供统一的串口操作接口,同时实现对串口硬件的精细化管理与适配。
[1].向下适配:兼容不同架构(x86/ARM/PowerPC 等)、不同厂商(TI/Freescale/Exar 等)、不同规格(8250/16550A/16750/XR16850 等)的 UART 硬件,处理寄存器映射、字节序、硬件缺陷等差异;

[2].向上抽象:为内核 TTY 子系统、控制台、用户态应用提供标准化的串口操作能力(收发数据、中断处理、FIFO 管理、RS485 仿真等)。
学习重点:
对比 ttynull,理解 tty 驱动如何对接实际硬件寄存器(如数据寄存器 THR/RBR、控制寄存器 LCR、状态寄存器 LSR);
掌握 tty 驱动中 “线路规程(line discipline)” 与硬件驱动的交互(ttynull 几乎没用到,而串口驱动是核心场景);
理解 tty 子系统的核心结构体(struct tty_driver/struct tty_operations)在实际硬件驱动中的完整实现;
初步接触 中断处理(串口的收发中断是驱动中最基础的中断场景)。
第二步:扩展到通用字符设备驱动(脱离 tty 子系统)
tty 驱动本质是字符设备的 “特殊形态”,掌握通用字符设备驱动能理解驱动开发的通用框架,为后续学习块设备、PCI 驱动打基础:
代码路径:经典字符设备驱动:drivers/char/mem.c(/dev/mem/zero/null 等设备,和 ttynull 同源,但更通用);
学习重点:掌握字符设备的核心流程:cdev_init/cdev_add–>设备号申请–>file_operations 实现–>设备节点创建;
对比 tty 驱动的 tty_operations 和通用字符设备的 file_operations,理解两者的异同;
学习驱动中的内存管理(kmalloc/kfree、vmalloc)、并发控制(spinlock/mutex,串口驱动中已初步接触);
理解驱动与用户空间的交互(copy_to_user/copy_from_user)。
第三步:深入到 “带总线 / 平台适配” 的驱动
前面的驱动要么无硬件,要么是简单寄存器操作,接下来需要理解 Linux 驱动的 “设备模型” 核心 —— 总线、设备、驱动分离:
优先学 platform 驱动(最通用的平台设备驱动):
代码路径:drivers/tty/serial/8250/8250_of.c(基于 platform 总线的 8250 串口驱动);
学习重点:platform_device 结构体、设备树(Device Tree)与驱动的对接(of_match_table)、资源申请(request_mem_region/ioport_map);
可选学 PCI 驱动(PC 端最常见的总线驱动):
代码路径:drivers/tty/serial/8250/8250_pci.c;
学习重点:PCI 设备的枚举、BAR 空间映射、PCI 驱动的 probe/remove 流程。
第四步:进阶到更复杂的驱动场景(按需选择)
完成前三步后,应该差不多掌握了驱动开发的核心基础,接下来可根据方向深入:
中断与 DMA(硬件驱动核心):
代码路径:drivers/tty/serial/8250/8250_dma.c(串口 DMA 收发);
学习重点:中断顶半部 / 底半部(tasklet/workqueue)、DMA 通道申请与配置、中断共享。
学习技巧:
[1].对比学习:始终以 ttynull 为基准,对比后续驱动新增的逻辑(如硬件寄存器、中断、总线适配),明确 “新增代码解决了什么问题”;
[2].边看边搜:遇到不懂的结构体(如 struct uart_port),用 kernel-doc 查看内核注释(make kerneldocs 或在线查 kernel.org 文档);
[3].动手验证:可以在 qemu 中运行内核,通过 cat /proc/tty/drivers/ls /dev/ttyS* 观察串口驱动的加载,或修改简单驱动(如给 ttynull 加个打印)编译测试。
总结
我计划的学习路径核心是:ttynull–>ttyserial(8250)–>通用字符设备–>platform/PCI 驱动–>中断 / DMA / 块设备 / 网络设备,由 “无硬件” 到 “有硬件”、由 “单功能” 到 “完整设备模型” 逐步深入;
重点掌握 tty 子系统与通用字符设备的衔接、硬件寄存器操作、中断处理、Linux 设备模型(总线 / 设备 / 驱动分离)这四大核心;
以 8250 串口驱动为核心案例,它几乎涵盖了字符设备驱动的所有基础知识点,是入门的最佳范本。
以上为全文内容。
这里是女程序员的笔记本
15年+嵌入式软件工程师兼二胎宝妈
分享读书心得、工作经验,自我成长和生活方式。
希望我的文字能对你有所帮助
夜雨聆风
