news 2026/9/7 5:01:17

高通平台新增QMI接口实战:从内核配置到用户态验证全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高通平台新增QMI接口实战:从内核配置到用户态验证全流程

简介:面向高通平台驱动、协议栈或modem相关开发工程师,在QMI框架中增加新接口是功能定制与移植时的常见需求,若不清楚底层消息表与类型表的注册规则,很容易在运行时出现接口找不到或类型错位的问题。文档以高通LE2.2/GNSS DRV FLOW为实例,系统梳理了从IDL生成到消息表、类型表落位的完整关键路径。作者逐步说明了uim_remote_message_table_v01、loc_message_table_v02、uim_remote_type_table_v01等具体表项的定位方法,并给出两个必须对照确认的位置:新增message必须追加到message_table末尾,且其type由在message_table中的位置决定;同时,user_data类型还需要同时确认它在uim_remote_type_table_v01中的索引和uim_remote_qmi_idl_type_table_object_referenced_tables_v01中的位置,避免两层引用关系错配。文档还对inheritance_obj->p_type_table->p_referenced_tables这类指针链路做了备注,便于在实际代码中快速索引与排错;整体为单个docx文件,共291KB,文字精炼、步骤明确,适合在修改代码时对照查阅。已有12212人学习下载,对于正在做高通平台QMI二次开发、modem/GNSS功能扩展或接口调试的工程师,是一份能直接落地的实操笔记。

1. 背景先行:为什么要在高通平台增加QMI接口

做过高通平台驱动开发的人应该都有体会,QMI(Qualcomm MSM Interface)这套协议栈就像一块跳棋板,上层应用要到modem(调制解调器)那边取数据,不经过它基本走不通。前阵子接到一个需求,要在现有的AP侧Linux系统里新增一个QMI服务通道,把模组的信号质量、驻网状态、SIM卡信息这些数据实时捞回来给业务层用。整趟走下来,涉及内核配置、设备树、驱动注册、端口枚举和用户态验证,踩了不少坑,这里把关键点整理一下,当作是给自己的备忘。

QMI本质上是一套基于共享内存或USB传输的IPC(进程间通信)协议,它跑在高通的modem和AP(应用处理器)之间。Linux侧通常通过内核里的qrtr(Qualcomm Remote Transport)层来承载QMI消息,用户态则通过libqmi库或qmicli工具来发请求、收响应。所谓的“增加QMI接口”,在不同场景下有不同含义:是在现有通道上新增一个服务(比如新增一个自定义QMI service),还是增加一个物理逻辑上的QMI端口(比如加一路USB QMI网卡),甚至是新增一个独立的QRTR节点把数据路由到新设备。我这次的需求偏向第二种,需要在现有系统里增加一个可用的QMI数据通道,同时确认它在用户态能正常枚举。

这篇内容适合谁看?两种人最合适:一是刚接手高通平台驱动开发没多久、对QMI框架还停留在“听说过”阶段的工程师,二是做上层通信应用、需要和modem打交道但不清楚底层链路怎么设计的同学。看完你至少能明白:一个QMI接口从内核到用户态要走通,需要哪些环节、每个环节卡住会是什么现象,以及怎么快速定位问题。

2. 动手之前先想清楚:QMI接口的整体链路与关键配置项

2.1 一条QMI通道从内核到用户态要经过哪些环节

一条可用的QMI接口,数据路径大致是这样的:modem侧的服务(比如DMS、NAS、UIM)通过共享内存或标准接口把消息发出来,AP侧的内核qrtr驱动负责将消息从物理链路(比如smem共享内存、rpmsg远程消息传递、或USB)上收下来,然后按服务ID和端口号分发给对应的套接字。用户态进程通过AF_QIPCRTR协议族的socket直接连接某个service_id:port,就能收发QMI报文。

要“增加”一个接口,最核心的几个改动点分别是:设备树节点、驱动绑定、QRTR端口分配、用户态库的编译选项。任何一环没对上,结果就是接口不存在、枚举失败或者发消息无响应。

以我这次的项目为例,平台是高通SM8250,系统采用标准Linux内核(版本5.4),modem侧固件已内置了目标QMI服务。我需要做的,其实是在AP侧确认/新增对应的QRTR服务端口,并让用户态能通过/dev/qrtr或者直接socket访问。某些场景下还需要把新增接口以网络设备形式暴露出(比如QMI WWAN网卡),那就还要配置rmnet通道。

2.2 内核相关配置项梳理

内核里与QMI强相关的配置项,对照Kconfig整理了一张表,方便排查问题时快速核对:

配置项作用缺失时的典型现象
CONFIG_QRTR启用QRTR协议核心框架无法创建AF_QIPCRTR套接字
CONFIG_QRTR_SMD基于共享内存(Shared Memory)的QRTR传输层AP和Modem之间的服务列表为空
CONFIG_QRTR_TUN提供内核态到用户态的测试回环通道某些调试工具无法使用
CONFIG_RPMSG远程处理器消息传输基础与ADSP/CDSP通信异常
CONFIG_QCOM_SMEM共享内存管理modem内存映射失败,服务不可见
CONFIG_USB_NET_QMI_WWAN通过USB承载的QMI/wwan网卡驱动USB接口下找不到QMI网卡节点

我在新内核上第一次编译时,发现CONFIG_QRTR已默认打开,但CONFIG_QRTR_SMD没有勾选,导致系统启动后QRTR总线没有设备,用户态qrtr-lookup查不到任何服务。这个问题很隐蔽,因为内核编译不报错,只有开机后服务列表一片空白,排查起来容易被忽略。

提示:修改内核配置后,务必确认新的kernel镜像真的烧进去了。曾经遇到过改完配置编译完,结果fastboot刷错了分区表,整半天全白忙。

2.3 设备树节点的作用与典型结构

设备树在高通平台里决定了驱动能否被实例化和硬件资源(中断、内存地址、时钟、电源域)是否就位。QMI相关设备树节点主要集中在/sys/firmware/devicetree/base/soc/目录下,典型的SMD边缘节点长这样:

smd-edge { compatible = "qcom,smd-edge"; label = "modem"; qcom,smd-edge = <0>; qcom,smd-channel = "APPS_RIV"; qcom,smd-irq = <&tlmm_pinmux 32>; ... };

如果是新平台、新modem,光看默认设备树可能不够,需要确认对应的smd通道名和中断号是否与modem侧释放的通道一致。高通各平台的默认配置一般都能用,但如果做了modem侧裁剪,比如把某个服务迁移到了新通道,那AP侧设备树的通道映射就得同步改。

另外,新的设备树绑定可能不再使用传统SMD,而是走rpmsg节点。遇到这种情况,要确认glink子节点配得对不对。Glink平台节点通常长这样:

smd-edge { compatible = "qcom,glink-smem"; qcom,remote-pid = <1>; transport = "smem"; mboxes = <&apcs_glb 12>; mbox-names = "smd"; label = "mpss"; };

这种差别虽然不影响最终用户态看到的QMI服务,但改错了会导致整个modem链路起不来,system log里能看到明显的超时错误。所以拿到任务之后,第一件事不是急着写代码,而是对照现有设备和平台文档,看走的是SMD、RPM还是Glink通道。

3. 实操过程:从内核驱动到用户态接口的完整烧录验证

3.1 步骤一:核对硬件和modem侧服务状态

在动任何代码之前,先确认硬件上modem部分已正常启动。启动后第一时间抓串口日志,搜关键字modemmpsssubsys,正常状态是:subsys_modem: modem is ready或者ssr_remoteproc: modem boot success之类的信息。

如果modem还没起来就去看QMI,等于无源之水。建议先跑一轮底层的开机日志,“有没有加载”永远先于“好不好用”。

确认modem起来之后,再通过qrtr-lookup或者直接读QRTR节点,看modem侧上报了哪些服务。操作方式是:

# 编译并放入板端的工具 qrtr-lookup

正常会输出类似这样的内容:

service 17 version 1 instance 0 node 1 service 17 version 2 instance 0 node 1

这里的service号就是QMI服务类型(17是DMS,18是NAS,21是UIM,等等),node表示由哪个远程处理器发布的服务。若这里列不出来,说明内核QRTR链路有问题,先回头查内核配置和设备树,暂时不需要动任何上层代码。

3.2 步骤二:配置内核并编出可用镜像

确认modem侧OK后,进入内核源码目录,勾选相关选项。建议直接用make menuconfig搜索关键字,逐个确认:

make ARCH=arm64 menuconfig

依次check以下项:

  • Networking support > Bluetooth > QIPC(部分平台结构下有嵌套,不强制)
  • Networking support > QMI helpers
  • Networking support > QRTR
  • Device Drivers > Remoteproc > QCOM Shared Memory
  • Device Drivers > Network device support > USB Network Adapters

如果项目用的是AOSP或Yocto环境,改完配置后需要重新生成defconfig,不要图省事直接改arch/arm64/configs/下的既有文件,最好基于厂商提供的base配置文件修改,以便后续diff和review。

编译完成后,确认生成的Image.gzdtb时间戳正常。烧录方式因平台而异,常见的是fastboot flash bootfastboot flash dtbo。烧录完成后先引导系统,执行uname -a确认内核版本与编译时间,确保镜像生效。

注意:部分平台存在boot.img内嵌dtb的打包方式,编译后需要显式重新打包(比如使用mkbootimg --dtb),否则新设备树不生效,白白烧录。

3.3 步骤三:确认驱动绑定和QRTR服务可见性

系统起来后,先看设备树节点是否被正确解析,然后检查QRTR总线上挂载的设备:

# 查看相关平台的设备节点 find /sys/firmware/devicetree/base -name "*smd*" -o -name "*glink*"

再看内核日志里相关驱动的probe情况:

dmesg | grep -E "qrtr|smd|glink|rpmsg"

正常会看到类似:

qrtr: registered router qrtr: node 0 is up qrtr_smd: QMI SMD transport registered

如果QRTR已注册但看不到node 1 is up,大概率说明SMD/Glink通道没有与modem建立连接。最有效的排查方法是,在板端依次查看QRTR节点状态:

ls /sys/kernel/debug/qrtr/ cat /sys/kernel/debug/qrtr/names

names文件列出的内容就等价于用户态qrtr-lookup看到的结果,但多一条直接内核态的信息。若发现modem侧节点始终没有出现,建议回头重点检查qcom,smem-state、中断号这些和平台ROM固件约定好的参数。

3.4 步骤四:用户态编译libqmi并验证接口

内核链路通了,接下来把用户态工具准备好。高通官方推荐的是libqmi,源码在freedesktop的git仓库上(https://gitlab.freedesktop.org/mobile-broadband/libqmi),克隆后正常编译:

git clone https://gitlab.freedesktop.org/mobile-broadband/libqmi.git cd libqmi meson build && ninja -C build

编译选项里重点确认两个:一个是--enable-qrtr,另一个是--enable-mbim。从libqmi 1.24版本开始,QRTR支持作为独立构建选项,老版本里可能需要额外指定。编译完成后,把qmicli和配套工具推到板端或交叉编译进根文件系统。

验证接口是否新增成功,可以用标准的qmicli命令来查询modem基本信息:

qmicli -d /dev/cdc-wdm0 --dms-get-ids qmicli -d /dev/cdc-wdm0 --nas-get-signal-info

这里的/dev/cdc-wdm0是USB QMI设备节点。但如果是走共享内存而非USB,那么-d参数就不适用,这时候要改用--device-open-qrtr方式:

qmicli -p --device-open-qrtr -d 17 --dms-get-ids

其中17是目标服务ID。这种方式能直接验证QRTR通道下服务是否可交互。如果查询能返回Device IDIMEI,说明整条链路已经通了。

注意:qmicli默认会对modem加锁,如果同时开了多个会话,可能会提示“Device is already open”。调试时建议使用带-p参数进入“骚扰模式”,直接绕过锁。

4. 常见问题与排查速查表

4.1 服务列表为空:先别急着怀疑驱动

遇到qrtr-lookup什么都没有,大多数人第一反应是改驱动。实际上,多数时候问题出在内核配置或modem固件没有完全启动。这里给一个排错顺序,实测最省时间:

现象第一步排查第二步排查第三步排查
qrtr-lookup无输出检查modem启动日志确认CONFIG_QRTR_SMD存在检查SMD通道中断配置
服务列表有内容但连不上确认服务ID和实例号正确检查多个client是否占用端口qmicli -p强制访问
发送请求超时确认modem当前状态(飞行/异常重启)检查功耗管理是否休眠抓包看是否有response
设备节点不存在确认cdc-wdm驱动枚举看USB描述符有没有QMI接口检查内核USB规则过滤

4.2 驱动绑定失败常用的三板斧

第一种:设备树节点存在但驱动未probe。先看driver_override是否干扰了匹配:

ls /sys/bus/platform/devices/*/driver

再用of_device_is_available检查节点状态。有时候厂商的默认设备树里该节点被status = "disabled"了,此时需要显式置为okay

第二种:节点匹配了但probe返回错误。常见原因是中断申请失败或mbox请求失败,内核日志里一般有明显报错:

smd-edge: failed to request smd interrupt

这种大多数是设备树里interrupts或者mboxes配置和实际硬件不一致,换一组正确的pin或mbox名称即可。

第三种:probe成功但QRTR依旧不通。这种情况多半不是驱动本身问题,而是modem侧固件没有释放该服务。可以在modem侧通过QXDM(高通调试工具)抓取DIAG_LOG确认服务端是否真的存在,不要一上来就怀疑AP侧代码。

4.3 用户态工具查询无响应的隐藏原因

用户态查询无响应,容易被忽视的原因是QRTR包被功耗管理挡住了。系统在深度睡眠时,共享内存总线可能不工作,这时qmicli发出的消息就“悬空”了。排查方式是查看suspend前后dmesg是否有USB或IPC相关状态切换。

另一种常见情况是多个进程同时打开了同一个QMI端口。因为QMI通道是点对点单服务器模型,多个客户端同时使用很容易引发冲突。这时候要么用qmicli -p抢占,要么在架构上做一个QMI代理服务,所有业务统一通过这个代理访问modem侧,避免端口争抢。

经验:生产环境千万不要让每个上层应用都直接连QMI服务端口,很容易把modem侧的服务搞挂。最稳妥的做法是写一个常驻的middleware(比如基于libmbim或自定义QMI daemon),统一管理通道和请求分发。

5. 一些值得留意的细节与心得

增加QMI接口这件事,表面上看就是打开一个配置、写一段树节点、编一次内核,但真要稳定复现,还是有不少坑。

第一个细节是内核版本和工具链版本要匹配。某次我在5.4内核上手动升级了libqmi到1.30,结果新版库默认启用了新的qrtr连接逻辑,跟旧内核有个小功能不兼容,导致查询消息一直发不出去。最后回退到1.26版本解决。所以,升级用户态库之前,千万确认内核版本年份和库版本差不多时间,别差得太远。

第二个细节是多核平台的affinity问题。在高通平台,AP侧有多个remoteproc(比如modem、ADSP、CDSP),它们的QRTR节点号不同。写自动化脚本时不要写死node 1,最好通过服务发现动态获取节点号,否则下次modem的编号有变化,你的脚本就废了。

第三个细节是安全策略。部分平台开启了对QRTR socket的SELinux限制。增加QMI接口后,如果应用层反映“socket创建失败”或“bind失败”,但内核日志却干干净净,大概率是SELinux策略问题。此时抓avc denied日志,并针对对应进程补充allow规则即可。

开发过程中我也养成了一些好习惯,放在这给大家参考:

  • 每次动手前,先把板端当前状态(内核hash、设备树时间戳、modem固件版本)完整记录一次,形成基线。改坏状态有地方退。
  • 每次改动尽量只碰一个变量。比如内核配置批次、设备树树节点批次、用户态工具批次分开验证,不要混在一起排查。
  • 所有验证脚本统一放到一个角落目录管理,方便后续回归和交接。

初次接触QMI这套体系的人,可能会被一堆模块缩写劝退。但其实把它拆成“modem侧发布服务、内核负责路由、用户态负责访问”三个环节,问题定位就有清晰方向。接口能不能通,每一步都有自己的验证手段,真正把每层的状态日志打扎实了,增加一个新接口不过是个日常工程活。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 5:01:11

C#上位机集成虹软ArcFace SDK实现离线人脸识别实战

简介&#xff1a;一套基于虹软免费SDK的C#人脸识别Demo完整版&#xff0c;面向需要在.NET环境中快速实现人脸检测、人脸对比与人脸检索的开发者&#xff0c;适合作为WinForms桌面项目的参考工程。压缩包内共包含二十五份文件&#xff0c;核心是十七份C#源代码文件&#xff0c;完…

作者头像 李华
网站建设 2026/9/7 5:00:12

Verilog计数器必知:阻塞与非阻塞赋值底层原理解析与实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 4:59:01

PTN业务配置核心流程与故障排查实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 4:56:37

局域网NTP时间同步服务器搭建:chrony配置与客户端接入指南

简介&#xff1a;这是一套面向小型局域网的时间同步工具&#xff0c;包含服务器端与客户端程序&#xff0c;适合需要在无外部NTP条件下自行校准设备时钟的IT运维或开发人员。方案以Visual C编写客户端&#xff0c;通过自定义协议与指定服务器通信&#xff0c;完成时间请求、响应…

作者头像 李华
网站建设 2026/9/7 4:55:21

重复文件清理软件推荐:Czkawka 免费去重工具 5 步上手全解

重复文件清理软件推荐&#xff1a;Czkawka 免费去重工具 5 步上手全解 【免费下载链接】czkawka Multi functional app to find duplicates, empty folders, similar images etc. 项目地址: https://gitcode.com/GitHub_Trending/cz/czkawka 如果你正在找一款重复文件清…

作者头像 李华