Ubuntu22.04.1
Linux版本5.19.0-32-generic
运行Qt串口通信 m_serialPort->open(QIODevice::ReadWrite) 时,总是失败。
负责硬件的同事说可能是需要安装ch340驱动。
WCH官网下载驱动 CH341SER_LINUX.ZIP
ncyf@NCYF:~/Downloads$ unzip -O GBK CH341SER_LINUX.ZIP
Archive: CH341SER_LINUX.ZIP
creating: CH341SER_LINUX/
inflating: CH341SER_LINUX/ch34x.c
inflating: CH341SER_LINUX/Makefile
inflating: CH341SER_LINUX/readme.txt
ncyf@NCYF:~/Downloads$
如果直接编译,会报错
ncyf@NCYF:~/Downloads$ cd CH341SER_LINUX/
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ ls
ch34x.c Makefile readme.txt
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ make
make -C /lib/modules/5.19.0-32-generic/build M=/home/ncyf/Downloads/CH341SER_LINUX
make[1]: 进入目录“/usr/src/linux-headers-5.19.0-32-generic”
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
You are using: gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
CC [M] /home/ncyf/Downloads/CH341SER_LINUX/ch34x.o
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c: In function ‘ch34x_close’:
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:591:9: error: unknown type name ‘wait_queue_t’; did you mean ‘wait_event’?
591 | wait_queue_t wait;
| ^~~~~~~~~~~~
| wait_event
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:591:22: warning: unused variable ‘wait’ [-Wunused-variable]
591 | wait_queue_t wait;
| ^~~~
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:590:14: warning: unused variable ‘timeout’ [-Wunused-variable]
590 | long timeout;
| ^~~~~~~
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:589:13: warning: unused variable ‘bps’ [-Wunused-variable]
589 | int bps;
| ^~~
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c: At top level:
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:1297:27: error: initialization of ‘unsigned int (*)(struct tty_struct *)’ from incompatible pointer type ‘int (*)(struct tty_struct *)’ [-Werror=incompatible-pointer-types]
1297 | .write_room = ch34x_write_room,
| ^~~~~~~~~~~~~~~~
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:1297:27: note: (near initialization for ‘ch34x_device.write_room’)
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:1298:28: error: initialization of ‘unsigned int (*)(struct tty_struct *)’ from incompatible pointer type ‘int (*)(struct tty_struct *)’ [-Werror=incompatible-pointer-types]
1298 | .chars_in_buffer = ch34x_chars_in_buffer,
| ^~~~~~~~~~~~~~~~~~~~~
/home/ncyf/Downloads/CH341SER_LINUX/ch34x.c:1298:28: note: (near initialization for ‘ch34x_device.chars_in_buffer’)
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:257:/home/ncyf/Downloads/CH341SER_LINUX/ch34x.o] 错误 1
make[1]: *** [Makefile:1850:/home/ncyf/Downloads/CH341SER_LINUX] 错误 2
make[1]: 离开目录“/usr/src/linux-headers-5.19.0-32-generic”
make: *** [Makefile:5:default] 错误 2
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
原因在 readme.txt 里面有说明
// ChangeLog
// 1.0 - 1.1 modified to solve transmition between ch341 and ch341
// 1.1 - 1.2 Support high Linux kernel
Instructions
Note: 1.Please run followed executable programs as root privilege
2.Current Driver support versions of linux kernel range from 2.6.25 to 3.13.x
3.Current Driver support 32bits and 64bits linux systems
Usage:
(load or unload linux driver of CH34x)
//compile
#make
//load ch34x chips driver
#make load
//unload ch34x chips driver
#make unload
// 1.2 - 1.3 Fix some bugs
第七行Current Driver support versions of linux kernel range from 2.6.25 to 3.13.x的意思是linux内核的当前驱动程序支持版本从2.6.25到3.13.x
而我的是5.19.0-32-generic
所以需要去查看ch34x.c的 源代码,直接复制到CH341SER_LINUX/ch34x.c 中,重新make
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ make
make -C /lib/modules/5.19.0-32-generic/build M=/home/ncyf/Downloads/CH341SER_LINUX
make[1]: 进入目录“/usr/src/linux-headers-5.19.0-32-generic”
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
You are using: gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
CC [M] /home/ncyf/Downloads/CH341SER_LINUX/ch34x.o
MODPOST /home/ncyf/Downloads/CH341SER_LINUX/Module.symvers
CC [M] /home/ncyf/Downloads/CH341SER_LINUX/ch34x.mod.o
LD [M] /home/ncyf/Downloads/CH341SER_LINUX/ch34x.ko
BTF [M] /home/ncyf/Downloads/CH341SER_LINUX/ch34x.ko
Skipping BTF generation for /home/ncyf/Downloads/CH341SER_LINUX/ch34x.ko due to unavailability of vmlinux
make[1]: 离开目录“/usr/src/linux-headers-5.19.0-32-generic”
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ ls
ch34x.c ch34x.ko ch34x.mod ch34x.mod.c ch34x.mod.o ch34x.o Makefile modules.order Module.symvers readme.txt
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
此时目录下,已生成.ko文件,说明 make 成功了。
载入模块(设备驱动程序)
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ sudo make load
[sudo] ncyf 的密码:
modprobe usbserial
insmod ch34x.ko
insmod: ERROR: could not insert module ch34x.ko: Key was rejected by service
make: *** [Makefile:10:load] 错误 1
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
错误提示:Key was rejected by service
说明.ko文件需要签名。
查看驱动签名情况
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ ls
ch34x.c ch34x.ko ch34x.mod ch34x.mod.c ch34x.mod.o ch34x.o Makefile modules.order Module.symvers readme.txt
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ hexdump -C ch34x.ko | tail
000566f0 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00056700 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00056710 00 00 00 00 00 00 00 00 f8 cd 02 00 00 00 00 00 |................|
00056720 37 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |7...............|
00056730 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056740 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00056750 00 00 00 00 00 00 00 00 20 59 05 00 00 00 00 00 |........ Y......|
00056760 e0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056770 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056780
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
此时没有签名。
首先依赖mokutil和shim-signed
sudo apt install mokutil
sudo apt install shim-signed
sudo update-secureboot-policy --new-key
生成的证书(MOK.der)和私钥(MOK.priv)位于 /var/lib/shim-signed/mok/ 目录下。
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=Descriptive name/"
导入签名证书
sudo mokutil --import /var/lib/shim-signed/mok/MOK.der
重新启动
电脑启动 UEFI 询问您是否要更改安全设置,选择”Yes”。
将签名写入驱动
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ ls
ch34x.c ch34x.ko ch34x.mod ch34x.mod.c ch34x.mod.o ch34x.o Makefile modules.order Module.symvers readme.txt
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ hexdump -C ch34x.ko | tail
000566f0 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00056700 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00056710 00 00 00 00 00 00 00 00 f8 cd 02 00 00 00 00 00 |................|
00056720 37 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |7...............|
00056730 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056740 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00056750 00 00 00 00 00 00 00 00 20 59 05 00 00 00 00 00 |........ Y......|
00056760 e0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056770 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00056780
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 /var/lib/shim-signed/mok/MOK.priv /var/lib/shim-signed/mok/MOK.der ch34x.ko
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ hexdump -C ch34x.ko | tail
000568d0 c4 6c 1c 49 a8 4d e4 68 b2 c2 ab c1 a6 4f f7 45 |.l.I.M.h.....O.E|
000568e0 bd 9b 33 23 f1 3d 38 41 29 bb 05 5f 81 16 73 62 |..3#.=8A).._..sb|
000568f0 b2 8c 2a f6 9c 7e e2 e9 1a 0f 79 32 9e b5 8e 6b |..*..~....y2...k|
00056900 50 0e a4 49 e4 06 59 79 8f 81 ef 7c df 9d e9 1f |P..I..Yy...|....|
00056910 3b 2f 15 0f 12 43 b9 5d 05 09 f3 d8 0e bc 8b aa |;/...C.]........|
00056920 e2 0a d7 bf cc 01 24 04 36 de 93 00 00 02 00 00 |......$.6.......|
00056930 00 00 00 00 00 01 ab 7e 4d 6f 64 75 6c 65 20 73 |.......~Module s|
00056940 69 67 6e 61 74 75 72 65 20 61 70 70 65 6e 64 65 |ignature appende|
00056950 64 7e 0a |d~.|
00056953
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
此时驱动程序数据中有~Module signature appended~,可知已写入签名。
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ sudo make load
modprobe usbserial
insmod ch34x.ko
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
对比之前的,确实载入成功了。
ncyf@NCYF:~/Downloads/CH341SER_LINUX$ sudo make load
[sudo] ncyf 的密码:
modprobe usbserial
insmod ch34x.ko
insmod: ERROR: could not insert module ch34x.ko: Key was rejected by service
make: *** [Makefile:10:load] 错误 1
ncyf@NCYF:~/Downloads/CH341SER_LINUX$
使用lsmod查看模块,发现已识别。
ncyf@NCYF:/lib/modules/5.19.0-32-generic/kernel/drivers/usb/serial$ lsmod
Module Size Used by
ch34x 24576 0
rfcomm 86016 4
有的博主说需要将目录中生成ch34x.ko文件复制到/lib/modules/$(uname -r)/kernel/drivers/usb/serial下,再使用lsmod查看模块,本人好像没做也行。
参考
解决Ubuntu22.04无法使用ch34x串口问题
linux secure boot(安全启动)下为内核模块签名
Linux驱动 - Ubuntu驱动签名