十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

开源鸿蒙内核配置与驱动三条路径—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】

开源鸿蒙内核配置与驱动三条路径—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】 框架的位置清楚了。今天说加一颗外设能走哪三条路以及选错路时为什么编译成功、板上却有时有节点、有时没有。现象很具体你menuconfig里把某个驱动勾成*编完、刷完dmesg里没有 probe。或者insmod r8188eu.ko报Key was rejected by service。或者超声波节点/dev/hcsr04好好的你又在 HCS 里给同一条 I2C 登记了一个 HDF 设备两边开始互相 NACK。原因不在芯片。开源鸿蒙这块 RK3568 上一个外设能走三条路进系统配置却分散在 defconfig、build_kernel.sh、设备树、HCS 四处。改错地方编译照样 exit 0。产品目录按教程代号rk3568_evb。现象menuconfig 勾了重启又没了cd out/kernel/src_tmp/linux-5.10 make LLVM1 ARCHarm64 menuconfigCONFIG_FOOy当时在.config里。下一次./build.sh --product-name rk3568_evb --ccache跑完打开out/kernel/OBJ/linux-5.10/.configFOO又是is not set。原因板级build_kernel.sh每次都会用碎片 defconfig重新合成.config。menuconfig 改的是当前 OBJ 里那一份不是权威源。权威源有三处缺一处下一次合成就丢源码树里的 defconfig本次构建用的out/kernel/.../rockchip_linux_defconfig只对「此刻不重建、先测一把」有用device/board/rk/rk3568_evb/kernel/build_kernel.sh第 13 段的幂等sed/appendGN 的内核 action 还不跟踪device/board/。你只改了build_kernel.shninja 可能判定「内核没变」连合成都不跑。代码# device/board/rk/rk3568_evb/kernel/build_kernel.sh §13 MERGED_CFG CFG$KERNEL_SRC/arch/arm64/configs/rockchip_linux_defconfig set_y() { local k$1 if grep -q ^${k}y $CFG; then return 0 fi if grep -q ^# ${k} is not set $CFG; then sed -i s/^# ${k} is not set/${k}y/ $CFG else echo ${k}y $CFG fi } set_y CONFIG_EVB_MISC set_y CONFIG_CFI_PERMISSIVE # R8188EU 不能 set_y编完对产物不要信 exit 0grep ^CONFIG_EVB_MISC out/kernel/OBJ/linux-5.10/.config strings out/kernel/OBJ/linux-5.10/vmlinux | grep evb_misc | head.config是y而vmlinux里没有符号删out/kernel/checkpoint再编。现象staging 驱动一 insmod整板复位原因内核开了CONFIG_CFI_CLANGy加 ThinLTO。间接调用核对函数指针类型签名稍不对就 panic。staging 里 callback 类型不严是常态。bring-up 把 CFI 从「杀」降成「告警继续跑」CONFIG_CFI_PERMISSIVEy。代码写进 §13不要只在 menuconfig 里勾set_y CONFIG_CFI_PERMISSIVE rm -rf out/kernel/checkpoint ./build.sh --product-name rk3568_evb --ccache --build-target kernel --fast-rebuild --disable-package-imagegrep CFI_PERMISSIVE out/kernel/OBJ/linux-5.10/.config hdc shell dmesg | grep -i cfi现象insmod 报 Key was rejectedLoading of module with unavailable key is rejected insmod: failed to load /data/r8188eu.ko: Key was rejected by service脚本把失败打印成「跳过(已加载)」——2/dev/null ... || log 跳过把错误吞了。先lsmod。原因CONFIG_MODULE_SIG_FORCEy。未签名、或公钥和当前内核嵌的那把对不上一律拒绝。重编内核若重新生成certs/signing_key.pem旧.ko全废。钥匙必须固定在板级目录每次构建拷进内核树。代码device/board/rk/rk3568_evb/kernel/certs/signing_key.pem device/board/rk/rk3568_evb/kernel/certs/signing_key.x509CERT_SRC$BOARD_KERNEL/certs CERT_DST$KERNEL_SRC/certs mkdir -p $CERT_DST cp -f $CERT_SRC/signing_key.pem $CERT_DST/ cp -f $CERT_SRC/signing_key.x509 $CERT_DST/ROOT/path/to/OpenHarmony export PATH$ROOT/prebuilts/clang/ohos/linux-x86_64/llvm/bin:$PATH export KBUILD_OUTPUT$ROOT/out/kernel/OBJ/linux-5.10 cd $ROOT/out/kernel/src_tmp/linux-5.10 make LLVM1 LLVM_IAS1 CROSS_COMPILEaarch64-linux-gnu- ARCHarm64 \ Mdrivers/staging/rtl8188eu modules -j$(nproc) $KBUILD_OUTPUT/scripts/sign-file sha1 \ $KBUILD_OUTPUT/certs/signing_key.pem \ $KBUILD_OUTPUT/certs/signing_key.x509 \ drivers/staging/rtl8188eu/r8188eu.ko md5sum device/board/rk/rk3568_evb/kernel/certs/signing_key.x509 \ out/kernel/OBJ/linux-5.10/certs/signing_key.x509两份 x509 md5 必须一样。hdc file send r8188eu.ko /data/r8188eu.ko hdc shell lsmod | grep r8188eu || insmod /data/r8188eu.ko hdc shell dmesg | tail -20现象R8188EU 写成 y.config 里仍是 m原因drivers/staging/rtl8188eu/Kconfig有depends on m。y会被降回模块。必须当.ko打进镜像开机insmod。代码if grep -q ^CONFIG_R8188EUy $CFG; then sed -i s/^CONFIG_R8188EUy/CONFIG_R8188EUm/ $CFG fi if ! grep -q ^CONFIG_R8188EUm $CFG; then echo CONFIG_R8188EUm $CFG fiinitinit.rk30board.cfg的 cmds 只能放合法命令{ name: net_wifi_r8188eu, path: /vendor/bin/wifi-r8188eu-up.sh, once: 1 }脚本先lsmod再insmod失败留 stderr。三条路怎么选现象同一个超声波你写了 HDF Sensor 又写了内核hcsr04.c节点有时在、有时不在。原因Linux 原生驱动和 HDF 并存。一个硬件只能被一边 probe。选路看上层要什么只要/dev或 sysfs外设测试应用open→路径 A内核原生要用 HDF 的 GPIO/I2C/PWM API但还不是标准 Kit →路径 BHDF 平台要进桌面 / ADM / composer / 相机 Kit →路径 CHDF 外设模型触摸、音频、显示走 C。超声波、RFID、电机、LED、矩阵键盘走 A。选一条不要双边okay。路径 Amisc 字符设备接到内核目标DTS 一个节点misc_register出/dev/evb_misc用户态能read、能ioctl。代码evb_misc.h#ifndef EVB_MISC_H #define EVB_MISC_H #include linux/ioctl.h #define EVB_MISC_IOC_MAGIC E struct evb_misc_msg { unsigned int len; char text[120]; }; #define EVB_MISC_IOC_GET _IOR(EVB_MISC_IOC_MAGIC, 1, struct evb_misc_msg) #define EVB_MISC_IOC_SET _IOW(EVB_MISC_IOC_MAGIC, 2, struct evb_misc_msg) #endif用户态把linux/ioctl.h换成sys/ioctl.h。本产品用户态 32 位 musl.ko仍是 aarch64。ioctl 参数不要塞指针上面已经给compat_ioctl留了同一函数。代码evb_misc.c放到device/board/rk/rk3568_evb/kernel/drivers/由build_kernel.sh拷进drivers/misc/。// SPDX-License-Identifier: GPL-2.0 #include linux/module.h #include linux/platform_device.h #include linux/miscdevice.h #include linux/of.h #include linux/fs.h #include linux/uaccess.h #include linux/slab.h #include linux/mutex.h #include evb_misc.h struct evb_misc_dev { struct miscdevice misc; struct mutex lock; char buf[128]; size_t len; }; static ssize_t evb_misc_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct evb_misc_dev *edev file-private_data; ssize_t n; mutex_lock(edev-lock); n simple_read_from_buffer(ubuf, count, ppos, edev-buf, edev-len); mutex_unlock(edev-lock); return n; } static long evb_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct evb_misc_dev *edev file-private_data; struct evb_misc_msg msg; int ret 0; if (_IOC_TYPE(cmd) ! EVB_MISC_IOC_MAGIC) return -ENOTTY; mutex_lock(edev-lock); switch (cmd) { case EVB_MISC_IOC_GET: memset(msg, 0, sizeof(msg)); memcpy(msg.text, edev-buf, min(sizeof(msg.text) - 1, edev-len)); msg.len edev-len; if (copy_to_user((void __user *)arg, msg, sizeof(msg))) ret -EFAULT; break; case EVB_MISC_IOC_SET: if (copy_from_user(msg, (void __user *)arg, sizeof(msg))) { ret -EFAULT; break; } if (msg.len sizeof(edev-buf)) { ret -EINVAL; break; } memcpy(edev-buf, msg.text, msg.len); edev-buf[msg.len] \0; edev-len msg.len; break; default: ret -ENOTTY; break; } mutex_unlock(edev-lock); return ret; } static int evb_misc_open(struct inode *inode, struct file *file) { struct evb_misc_dev *edev container_of(file-private_data, struct evb_misc_dev, misc); file-private_data edev; return 0; } static const struct file_operations evb_misc_fops { .owner THIS_MODULE, .open evb_misc_open, .read evb_misc_read, .unlocked_ioctl evb_misc_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl evb_misc_ioctl, #endif }; static int evb_misc_probe(struct platform_device *pdev) { struct evb_misc_dev *edev; int ret; edev devm_kzalloc(pdev-dev, sizeof(*edev), GFP_KERNEL); if (!edev) return -ENOMEM; mutex_init(edev-lock); strscpy(edev-buf, evb_misc ready\n, sizeof(edev-buf)); edev-len strlen(edev-buf); edev-misc.minor MISC_DYNAMIC_MINOR; edev-misc.name evb_misc; edev-misc.fops evb_misc_fops; edev-misc.mode 0666; ret misc_register(edev-misc); if (ret) return ret; platform_set_drvdata(pdev, edev); dev_info(pdev-dev, /dev/evb_misc minor%d\n, edev-misc.minor); return 0; } static int evb_misc_remove(struct platform_device *pdev) { struct evb_misc_dev *edev platform_get_drvdata(pdev); misc_deregister(edev-misc); return 0; } static const struct of_device_id evb_misc_of_match[] { { .compatible rk3568,evb-misc }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, evb_misc_of_match); static struct platform_driver evb_misc_driver { .probe evb_misc_probe, .remove evb_misc_remove, .driver { .name evb-misc, .of_match_table evb_misc_of_match, }, }; module_platform_driver(evb_misc_driver); MODULE_LICENSE(GPL);Kconfigconfig EVB_MISC tristate rk3568_evb misc char skeleton default nMakefileobj-$(CONFIG_EVB_MISC) evb_misc.obuild_kernel.sh§13 拷源并set_y CONFIG_EVB_MISC。DTS/ { evb_misc: evb-misc { compatible rk3568,evb-misc; status okay; }; };compatible必须和of_device_id逐字符相同。开发期当.komake LLVM1 LLVM_IAS1 CROSS_COMPILEaarch64-linux-gnu- ARCHarm64 \ Mdrivers/misc evb_misc.ko -j$(nproc) $KBUILD_OUTPUT/scripts/sign-file sha1 \ $KBUILD_OUTPUT/certs/signing_key.pem \ $KBUILD_OUTPUT/certs/signing_key.x509 \ drivers/misc/evb_misc.ko hdc file send evb_misc.ko /data/evb_misc.ko hdc shell insmod /data/evb_misc.ko; cat /dev/evb_misc路径 BHDF 平台现象PWM 在/sys/class/pwm能转HDF 程序GpioRead失败。原因要在device_info.hcs登记policy 2用户态才 Bind 得到。Linux 已经 export 的脚HDF 再申请会抢。代码device_pwm :: device { device0 :: deviceNode { policy 2; priority 70; permission 0644; moduleName HDF_PLATFORM_PWM; serviceName HDF_PLATFORM_PWM_0; deviceMatchAttr rockchip_rk3568_pwm_0; } }改 khdf 刷 boot_linux改 uhdf 刷 vendor。改子 hcs 必须删 hcb。风扇演示走 sysfs 就够hdc shell echo 0 /sys/class/pwm/pwmchip0/export hdc shell echo 1000000 /sys/class/pwm/pwmchip0/pwm0/period hdc shell echo 500000 /sys/class/pwm/pwmchip0/pwm0/duty_cycle hdc shell echo 1 /sys/class/pwm/pwmchip0/pwm0/enable路径 CHDF 外设模型现象GT911 内核goodixprobe 成功桌面划不动或者坐标按 720×1280 缩。原因桌面走 Input 模型 HCS 的solutionX/Y。DTS 里 goodix 必须disabled。代码i2c2 { status okay; clock-frequency 100000; gt911_lvds: gt9115d { compatible goodix,gt911; reg 0x5d; status disabled; }; };inputAttr { solutionX 1024; solutionY 600; } busConfig { busType 0; busNum 2; }device_info.hcsmoduleName HDF_TOUCH_GT911policy 2preload 0。hdc shell cat /proc/bus/input/devices hdc shell ls /sys/bus/i2c/devices/2-005d/driver hdc shell i2cdetect -y -r 2现象对照现象原因先做什么menuconfig 勾了下次丢合成从 defconfig§13 来写进 §13三处同步.config 有、vmlinux 无符号ninja 没重跑内核删 checkpointinsmod Key rejected没签或钥匙换了固定 certssign-fileR8188EU 写 y 仍是 mKconfig depends on m保持 m开机 insmodinsmod 整板复位CFICFI_PERMISSIVEy有节点无 /dev驱动没编进来或 compatible 不对grep .config对 of_match用户态 so 段错误用 aarch64-linux-gnu 编了armv7 muslHDF 和内核抢 I2C两边都 okayDTS disabled 或 HCS 不要登记系列第 14 篇 · 芯片瑞芯微 RK3568 · OpenHarmony 4.1API 11 · Linux 5.10
返回列表