背景
前一段时间定位一个上位机通过USB-TMC连接下位机(基于RK3588平台)时界面发生卡顿的问题,发现USB-TMC驱动代码是放在内核源码树里跟内核一起编译的,觉着这样既不便于更换TMC 驱动版本(每次修改代码都要重编内核),也不便于将TMC驱动代码单独放到SVN管理(RK的build系统有16GB之巨,全部提交到SVN服务器吃不消),于是考虑将其挪到源码树外。
想参照自己之前在zynq平台上开发的TMC驱动代码,结果发现也是放在内核源码树内的,尴尬,无奈从头摸索,几经周折,特别是踩了RK3588的systemd服务adbd的坑之后,总算实现目标了。
实现方法
创建独立工程
在SVN为产品开辟的目录下新建TMC目录并检出,并添加以下Makefile
obj-m += ftmc.o
SDK = ~/RK3588_LINUX_NNEWN_NH102_SDK_Release
CROSS_PREFIX = $(SDK)/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-rockchip1031-linux-gnu-
KDIR = $(SDK)/kernel
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules modules ARCH=arm64 CROSS_COMPILE=$(CROSS_PREFIX)
clean:
rm -rf modules.order *.o *.mod Module.symvers *.mod.c *.ko *.cmd .*.cmd
注:ftmc.o是源码ftmc.c编译出来的目标文件
在adbd服务启动脚本里加载ko
目前USB function驱动基本都切换到configfs开发方式了,因此RK3588为所有function驱动提供了一个adbd服务,用于在Linux启动阶段自动在configfs里创建一些目录和文件,从而触发驱动的alloc_inst、alloc_func、bind等方法。
以前所有function驱动都编译到内核,因此该脚本只操作configfs即可启用function,但因为tmc驱动变成了独立的ko,因此要先insmod一个ko,具体做法是在/etc/init.d/adbd.sh
添加
if [ $TMC_EN = on ];then
if [ ! -e "${USB_FUNCTIONS_DIR}/tmc.gs0" ] ;
then
insmod /path/to/ftmc.ko # 就添加这一行
mkdir -p ${USB_FUNCTIONS_DIR}/tmc.gs0
ln -s ${USB_FUNCTIONS_DIR}/tmc.gs0 ${USB_CONFIGS_DIR}/tmc.gs0
fi
fi
禁用adbd服务的ExecStop语句
RK3588的adbd服务是这样写的:
这个写法是有问题的,会导致ExecStop
语句紧跟着ExecStart
执行,而adbd.sh的stop分支是会删除gadget的:
stop)
echo "none" > ${USB_CONFIGFS_DIR}/UDC # 这行命令会删除整个gadget,包括依附其上的各种function,比如TMC
if [ $ADB_EN = on ];then
start-stop-daemon --stop --oknodo --pidfile /var/run/adbd.pid --retry 5
fi
;;
因此不能这么写,我尝试过将服务的Type
改成oneshot
、simple
等,也试过添加RemainAfterExit=yes
、KillMode=none
等语句,均无法达到RK3588想要的效果——系统启动时执行且只执行ExecStart,系统关闭时执行且只执行ExecStop——或许systemd
可以增加一个新的Unit
类型😉
不管怎么样,现在的解决办法是禁用adbd服务的ExecStop
语句,反正嵌入式系统关机时就算设备没卸载也影响不大。
总结
configfs是个好东西,值得研究一番