CH340系列Linux驱动编译与内核适配实战
1. CH340驱动在Linux环境下的特殊挑战
第一次在Ubuntu 22.04上折腾CH340驱动时,我遇到了一个让人哭笑不得的情况——官方提供的驱动源码居然编译不过!这让我意识到,随着Linux内核版本的快速迭代,很多老牌硬件设备的驱动都需要手动适配。CH340作为国产USB转串口芯片中的性价比之王,在嵌入式开发和硬件调试领域应用广泛,但它的Linux驱动维护却明显跟不上内核更新的步伐。
我后来发现,这个问题主要源于Linux内核从5.0版本开始引入的一系列API变更。比如原先使用的wait_queue_t类型被重新定义,串口子系统中的write_room等回调函数的返回值类型也发生了变化。更麻烦的是,不同发行版的内核补丁策略各不相同,这就导致在Ubuntu、Debian、CentOS等系统上遇到的编译错误可能完全不同。有次我在一台Fedora 36的机器上,还遇到了usb_serial_port结构体成员访问权限的问题。
2. 驱动源码获取与预处理
2.1 官方源码的正确打开方式
南京沁恒官网提供的CH340驱动包(CH341SER_LINUX.ZIP)通常包含以下几个关键文件:
- ch34x.c(核心驱动源码)
- Makefile(编译脚本)
- readme.txt(基础说明)
但要注意,这个驱动包的最新版本还是2018年发布的,直接用在现代Linux系统上肯定会出问题。我建议下载后先做三件事:
- 解压到~/driver_ch340这样的纯英文路径
- 备份原始ch34x.c文件
- 查看当前内核版本(uname -r)
这里有个小技巧:如果官网下载速度慢,可以尝试在终端用wget直接获取:
wget https://www.wch.cn/downloads/CH341SER_LINUX_ZIP.html -O ch340_driver.zip2.2 内核头文件的秘密
编译驱动前必须确保安装了对应版本的内核头文件。在Ubuntu系系统上可以这样操作:
sudo apt update sudo apt install linux-headers-$(uname -r) build-essential有一次我在树莓派上编译时,发现默认源里的头文件版本和实际运行的内核不一致,这时候就需要手动指定:
sudo apt install linux-headers-5.15.0-1035-raspi3. 源码修改的实战技巧
3.1 必须做的五项修改
根据我的踩坑经验,现代内核(5.15+)环境下必须修改以下内容:
- 头文件补充:在ch34x.c开头添加
#include <linux/sched/signal.h>- 等待队列修复:注释掉老式声明
// wait_queue_t wait;- 返回值类型修正:这两个函数要改为unsigned int
static unsigned int ch34x_write_room(struct tty_struct *tty) static unsigned int ch34x_chars_in_buffer(struct tty_struct *tty)- 兼容性处理:对于5.17+内核需要处理tty_port结构体的变化
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) tty_port_tty_set(&port->port, tty); #else port->port.tty = tty; #endif- DMA相关警告:在6.0+内核需要添加
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))3.2 常见编译错误解决方案
遇到"implicit declaration"错误时,通常是因为内核移除了某些API。比如最近遇到的一个典型错误:
error: implicit declaration of function 'signal_pending'解决方法是在文件开头添加:
#include <linux/sched/signal.h>如果看到关于"wait_queue_t"的错误,说明你的内核版本较新,需要将相关代码改为:
wait_queue_entry_t wait;4. 编译与安装的完整流程
4.1 编译的玄学问题
执行make时可能会遇到各种神奇问题。这里分享几个实用参数:
make -j$(nproc) KERNELDIR=/lib/modules/$(uname -r)/build如果遇到BTF相关警告,可以暂时禁用:
make CONFIG_DEBUG_INFO_BTF=n我在一台NVIDIA Jetson设备上编译时,发现需要额外指定架构:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-4.2 安装的正确姿势
常规安装命令大家都知道:
sudo make install sudo depmod -a但有几个细节需要注意:
- 驱动文件应该放在/lib/modules/$(uname -r)/kernel/drivers/usb/serial/
- 安装后要执行modprobe加载模块
- 检查dmesg看是否有加载错误
我习惯用这个组合命令:
sudo cp ch34x.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ && \ sudo depmod -a && \ sudo modprobe ch34x && \ dmesg | tail -205. 验证与调试技巧
5.1 设备识别检查
插入CH340设备后,应该依次检查:
lsusb | grep 1a86 dmesg | tail ls /dev/ttyUSB*如果看到类似这样的输出就成功了:
Bus 003 Device 004: ID 1a86:7523 QinHeng Electronics CH340 serial converter5.2 串口回环测试
我推荐用picocom进行基础测试:
sudo apt install picocom picocom -b 115200 /dev/ttyUSB0更专业的测试可以用Python脚本:
import serial ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1) ser.write(b'Hello CH340\n') print(ser.readline())6. 内核升级后的应对策略
每次系统内核升级后,CH340驱动都需要重新编译。我开发了一个自动化脚本来自动处理:
#!/bin/bash cd ~/driver_ch340 make clean make sudo make install sudo modprobe -r ch34x sudo modprobe ch34x把这个脚本放在/etc/kernel/postinst.d/目录下,就能在每次内核更新后自动执行。
7. 深度定制与性能优化
7.1 修改PID/VID
如果需要支持自定义PID的设备,可以修改ch34x.c中的这些行:
#define CH340_VID 0x1A86 #define CH340_PID 0x75237.2 提高传输性能
在驱动源码中可以调整这些参数:
#define CH340_TX_BUFFER_SIZE 256 #define CH340_RX_BUFFER_SIZE 512但要注意,太大的缓冲区可能导致延迟增加。
7.3 解决RS485模式问题
如果需要RS485支持,要修改GPIO控制部分:
// 在ch34x_set_control函数中添加 if (control & CH340_CTRL_RS485) gpio_set_value(gpio_pin, 1); else gpio_set_value(gpio_pin, 0);8. 疑难杂症解决方案
遇到过最棘手的问题是驱动加载后设备不断断开重连。最终发现是电源管理导致的,解决方法是在modprobe配置中添加:
options ch34x enable_pm=0另一个常见问题是权限问题,可以通过udev规则解决:
echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", MODE="0666"' | sudo tee /etc/udev/rules.d/99-ch340.rules对于Arch Linux用户,AUR上有个维护更及时的驱动包:
yay -S ch340-dkms-git