RK3588 kernel-6.1 drivers/usb/serial 代码功能与实现原理
1. 子系统定位
USB Serial 在内核里为 USB 通信设备类(CDC)以外的「USB ↔ 串口/VCP」 设备(以及大量厂商专有 Bulk 协议)提供统一框架:
- 对上:暴露
/dev/ttyUSBn(主设备号 188,见USB_SERIAL_TTY_MAJOR) - 对下:通过
usb_interface→ usb_serial_driver → bulk/int URB 与硬件交互
架构文档:Documentation/usb/usb-serial.rst。
2. 模块划分(Makefile)
| 目标 | 组成 | 作用 |
|---|---|---|
usbserial(CONFIG_USB_SERIAL) |
usb-serial.o、generic.o、bus.o,可选 console.o |
核心:TTY、usb_serial 生命周期、generic 读写完、usb-serial 伪总线 |
*_SERIAL_* |
各 ftdi_sio.o、pl2303.o、ch341.o … |
芯片专用:probe、open/read_bulk/write_bulk、ioctl 等 |
专用驱动 depends on usbserial,由 MODULE_DEVICE_TABLE(usb, …) 触发 modprobe 加载 usbserial。
3. 核心数据结构(概念)
struct usb_serial_driver(<linux/usb/serial.h>):一种芯片/协议的「模板」,包含usb_driver(绑定usb_serial_probe)、id_table、端口数或calc_num_ports、open/close、bulk/int callback、attach/release等。struct usb_serial:一次 USB 设备 probe 对应的 逻辑适配器,持有dev、interface、端口指针数组、type。struct usb_serial_port:单个 TTY 端口,内含tty_port、minor、bulk/int URB 缓冲、serial反向指针。
minor 由 idr(serial_minors)分配,范围受 USB_SERIAL_TTY_MINORS(512) 限制。
4. 绑定与初始化:usb_serial_probe(usb-serial.c)
当 usbcore 匹配到某 usb_serial_driver:
search_serial_device选出type(持table_lock)。create_serial分配usb_serial与usb_serial_port。- 调用
type->probe(serial, id)(可选):子驱动拒绝则退出。 find_endpoints:扫描接口 bulk in/out、interrupt,必要时包含sibling接口。- 校验端点数量 ≥
type->num_bulk_*等要求。 calc_num_ports或固定type->num_ports决定 tty 端口个数。allocate_minors,setup_port_bulk_*/setup_port_interrupt_*填充 URB。device_add注册 端口设备,使其落到usb_serial_bus_type上。
原理:USB 接口驱动只做「发现资源 + 建 usb_serial」;真正注册 ttyUSB 发生在 端口 bus 的 probe(见下)。
5. usb_serial_bus_type(bus.c)
自定义 struct bus_type:usb-serial。
match:端口已绑定port->serial->type,与usb_serial_driver一一对应。probe(usb_serial_device_probe):调用driver->port_probe(可选),再tty_port_register_device,打印ttyUSB%d。remove:tty_unregister_device,port_remove。
原理:把 「端口」做成独立 device,便于 sysfs、电源管理与 TTY 设备节点 生命周期对齐。
6. TTY 路径(usb-serial.c)
usb_serial_tty_driver:tty_driver,major 188。serial_install:minor →usb_serial_port_get_by_minor,tty->driver_data = port,可选init_termios。serial_open→tty_port_open→serial_port_activate→type->open(tty, port)(通常usb_serial_generic_open+ 提交 读 URB)。serial_port_shutdown→type->close,usb_autopm_put_interface。- 写路径:
serial_write→ 子驱动或 generic 把数据塞进 bulk out URB。 - 读路径:bulk in complete →
tty_insert_flip_string→tty_flip_buffer_push。
电源:usb_autopm_get/put_interface 与 runtime PM 绑定,避免休眠与 URB 竞态。
7. generic.c:默认 Bulk 读写
usb_serial_generic_open:提交 bulk IN URB(usb_serial_generic_submit_read_urbs)。usb_serial_generic_write_bulk_callback / read_bulk_callback:维护 环形缓冲/链表,与 TTY 层对接。
多数简单设备 不重写 read/write,仅靠 generic + 正确端点探测 即可工作。
CONFIG_USB_SERIAL_GENERIC:调试用的 「generic」驱动,仅绑定模块参数 vendor/product,不推荐量产设备依赖。
8. 专用驱动模式(以常见芯片为例)
ftdi_sio、pl2303、ch341 等通常实现:
probe:波特率表、流控、私有 EEPROM/寄存器初始化。open:波特率、parity → USB 厂商命令 → 再 generic open。- *自定义
read_int_callback*:调制解调器状态线 CTS/DCD →tty_port_tty_wakeup/tty_schedule_flip。
usb-serial-simple.c:宏批量生成 仅 VID/PID + 固定端口数 的 usb_serial_driver,无专有协议。
9. 与其它子系统的关系
| 边界 | 说明 |
|---|---|
drivers/usb/class/cdc-acm.c |
CDC ACM 走另一套 TTY(/dev/ttyACM),不经过 usb-serial 核心 |
usbcore |
枚举、URB;usb-serial 是普通 usb_driver |
drivers/usb/core/file.c |
USB 字符设备 minor 与 ttyUSB 无关(后者由 tty_driver 注册) |
10. 数据流简图
1 | 用户 read/write / termios |
11. 延伸阅读(本仓库)
| 文档 |
|---|
| drivers-usb-core详细分析.md |
| USB总线枚举匹配与数据传输分析.md |
基于 rk3588/kernel-6.1/drivers/usb/serial 源码归纳。
正在加载留言…