ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

MTK USB VCOM深度解析:从驱动原理到BROM刷机失败排查

2026/8/28 2:45:06 拓冰建站 浏览量
MTK USB VCOM深度解析:从驱动原理到BROM刷机失败排查 简介围绕USB虚拟串口、驱动匹配、BROM枚举等基础概念展开。首先解释MTK VCOM在设备端与主机端的双重含义并对比Linux gadget虚拟串口与Windows usbser.sys驱动加载机制接着梳理BROM、Preloader到Kernel各阶段USB枚举形态说明SP Flash Tool刷机连接失败与线材、供电、驱动签名及工具版本的关联。结合CH340等常见USB转串口芯片的差异阐明MTK VCOM本质是标准CDC ACM设备便于工程人员从通用串口视角理解与调试。最后给出设备端configfs配置、主机端自定义INF方法以及Linux下端到端验证实验。适合驱动开发、产线工具及维修场景快速定位问题。 插上USB线设备管理器里刚跳出“MediaTek PreLoader USB VCOM_Port”转眼又变成未知设备SP Flash Tool 卡在 BROM connection failed。这个场景搞MTK平台调试和维修的人基本都遇到过。其实MTK_USB_VCOM不只是“一个驱动安装包”那么简单它一头连着芯片开机第一段代码里的USB枚举逻辑另一头连着Linux内核的gadget虚拟串口源码中间还夹着PC侧usbser.sys的驱动匹配。这篇文章就从一个实际项目的角度把VCOM的来龙去脉、设备端源码结构、主机端驱动原理以及刷机时最常见的连接失败排查讲透适合刚接触MTK平台的驱动工程师、做产线工具开发的兄弟也适合天天刷机的维修师傅。1. 先搞清楚MTK USB VCOM到底是个什么东西1.1 两种语境下的VCOM别混为一谈MTK平台的VCOM这个词在不同场景下指两个东西但名字都叫VCOM很多人被绕晕过。第一种是设备端视角。MTK Android设备的内核里有一个USB虚拟串口节点通常是/dev/ttyGS0或者/dev/ttyACM0。这个节点不是硬件UART而是CPU在USB线上模拟出来的一个串口底层实现就是Linux内核的f_serial或者f_acmgadget驱动。工程师可以用它做调试输出、modem交互甚至当普通串口用。这种VCOM的本质是“USB Gadget虚拟串口”。第二种是主机端视角。开发或者维修时把设备插到电脑上设备管理器里出现“MediaTek PreLoader USB VCOM_Port”或者“MediaTek USB VCOM_Port”。这是PC通过USB枚举识别出来的虚拟COM口PC认为它是一个标准串口设备但实际上另一端不是某个物理串口芯片而是MTK芯片内部的BootROM或者Preloader正在跑代码。理解这两种语境的差别很重要。因为网上搜“mtk驱动下载”下载的驱动主要是给主机端用的让Windows能识别出VCOM口。而网上搜“MTK USB VCOM源码”通常是指设备端Linux内核里的gadget驱动源码。两者是同一件事的两端中间隔着一根USB线。1.2 一个生活化类比VCOM像临时应急门如果觉得抽象可以把VCOM想象成一栋大楼的应急门。大楼平时走正门也就是Android系统起来后的ADB/MTP但断电重启的瞬间门禁系统还没启动只有一条专用的应急通道可以进出。应急通道只在特定阶段存在等大楼的正门开了它就会关闭。MTK芯片每次上电最先跑的是芯片内部固化的BootROM代码。这时候内存还没初始化闪存驱动也没有内核更没起来但它可以在USB线上枚举出一个设备让PC能往芯片里送数据。这个枚举出来的设备就是VCOM口。等Preloader或者后续的DADownload Agent跑起来VCOM口可能会短暂断开再重新枚举因为USB描述符变了。所以你在设备管理器里看到端口名跳来跳去不是系统抽风而是芯片还处于启动早期阶段USB枚举的“身份”一直在切换。1.3 常见的三种枚举形态和PIDMTK平台不同阶段枚举出来的USB设备名称和PID都不一样。我整理了一个常见对照表注意PID会因为芯片型号和固件版本有差异以实际设备管理器里看到的为准。枚举名称出现阶段常见PID用途MediaTek PreLoader USB VCOM_PortBROM / Preloader阶段0x0003下载Preloader、DAMediaTek USB VCOM_PortDA / META模式0x0003或0x2000刷机工具与DA通信MTK USB Debug PortLK / Kernel早期0x0001或0x0002调试、底层日志MTK的USB Vendor ID固定是0x0E8D这个是MediaTek官方分配的所有相关硬件ID都以USB\VID_0E8D开头。当你在设备管理器里看到这个VID基本可以确认是MTK的设备下一步就是给它装驱动。2. 设备端源码虚拟串口f_serial是怎么在MTK内核里跑起来的2.1 从configfs到gadget的完整链路在Linux内核里USB Gadget框架分好几层。底层是UDC控制器驱动负责和具体硬件打交道中间是gadget层决定设备以什么角色出现在主机面前再往上就是一个个usb_function比如MTP、ADB、ACM串口等。MTK设备端VCOM用的就是f_serial.c或者f_acm.c这个usb_function实现。以f_acm.c为例核心流程是这样的内核启动时gadget驱动会注册一个acm_bind回调把ACM功能绑定到某个USB配置上主机通过set_configuration激活这个配置后acm_set_alt会被调用这时驱动会申请端点、使能Bulk IN/Bulk OUT和Interrupt IN端点之后数据通路就建立了PC往USB口发的数据会通过端点的URB到达设备端设备端再通过tty层送给用户态。很多MTK项目的内核里USB功能选择是通过configfs来动态配置的而不是写死在代码里。在Android 9之后的高通和MTK平台上configfs是主流方案。你会在系统的/config/usb_gadget/目录下看到类似g1、functions、configs这些目录。往functions目录里创建acm.0再把它链接到某个配置目录下这个虚拟串口就挂上去了。MTK和Android参考实现基本一致只是UDP驱动用的MTK私有USB控制器。2.2 u_serial与gs_serial的配合f_serial.c本身只管USB侧的事务真正连接USB和tty的是u_serial.c和gs_serial.c这两个文件。gs_serial.c里定义了USB侧的回调比如gs_alloc_requests、gs_start_tx、gs_rx_push这些。当USB主机发来数据URB完成回调会把数据放到一个接收缓冲区然后交给tty层。u_serial.c则实现了一个标准tty驱动注册成/dev/ttyGS0这样的节点。用户态程序打开这个节点后读写操作会经tty层转到gs_serial最终通过usb_ep_queue发到USB线上。数据流向大致是主机发数据 → USB端点URB完成 →gs_serial收到 → tty缓冲区 →/dev/ttyGS0→ 用户态程序读用户态程序写/dev/ttyGS0→ tty层 →gs_tty_write→usb_ep_queue→ USB端点 → 主机收我一开始读这段代码时被各种port、gser、acm的结构体绕晕。后来发现关键就是记住一句话USB侧和tty侧是两个世界gserial结构体是连接这两个世界的桥。弄懂了桥两边的接口再看代码就顺了。2.3 MTK DWS工具与板级DTS配置MTK平台和骁龙平台在工程习惯上有一个明显区别骁龙平台的dts文件往往是工程师直接在文本里改MTK平台早期更依赖一个叫DWSDevice Work Sheet的图形化工具。工程师在DWS里打开项目级别的dts工程文件勾选管脚功能、设置控制器开关保存后自动生成对应的dts/dtsi文本。和VCOM相关的板级配置通常就在这几个地方usb0节点要status okaydr_mode要配置成peripheral或者otg如果配成host设备就只能当USB主机插到电脑上自然不可能被识别成VCOM某些平台还需要检查mtk_usb相关节点的rdma、qmu中断是否正常使能。网上有人搜“mtk dws”多半就是在找这个工具来处理板级配置。实际经验是如果你发现插上电脑完全没有设备枚举先别急着怀疑驱动去DTS里看一眼dr_mode是不是被改成了host模式尤其是那些有USB扩展坞、OTG线材的项目角色切换逻辑一旦配置错整个USB功能都不生效。2.4 f_serial和f_acm的差别选错会有一堆坑设备端VCOM可以在f_serial和f_acm之间选两者都是虚拟串口但USB描述符有区别。f_serial实现的USB接口类是厂商自定义类Vendor SpecificWindows下如果没有对应inf会显示成未知设备。f_acm实现的是标准CDC ACM类设备描述符里标识成通信设备类Windows自带usbser.sys就能识别成COM口。MTK在BROM阶段自己实现了一套USB协议栈但对外枚举出的描述符走的是兼容CDC ACM的路线所以Windows才能直接识别出串口。而设备端Android里的f_serial通常给modem调试用主机端不一定认。如果自己做板级开发需要把虚拟串口接到PC上调试我建议优先用f_acm而不是f_serial省去一堆inf匹配的麻烦。3. Windows主机侧VCOM驱动到底装的是什么3.1 它和CH340、CP2102驱动有什么异同电脑上装驱动的逻辑其实都一样USB设备枚举后系统读取VID厂商ID和PID产品ID然后去匹配一个驱动。CH340、CP2102、FT232R这类芯片是独立的USB转串口芯片芯片内部固件已经写好了枚举描述符厂商提供对应驱动装好后PC就多出一个COM口。MTK VCOM的特别之处在于它没有一个独立串口芯片是MTK芯片内部CPU直接用USB控制器模拟出CDC ACM设备。对PC来说效果一样都是虚拟串口但真正的“固件”是MTK芯片的BootROM代码不像CH340那样能刷固件。拿对比表来看更直观设备VID:PID常见值PC驱动来源典型场景CH3401A86:7523沁恒官方驱动Arduino下载、USB转串口CP210210C4:EA60Silicon Labs驱动模块调试、路由器刷机FT232R0403:6001FTDI VCP驱动工业设备调试MTK PreLoader VCOM0E8D:0003MTK官方驱动包刷机、DA下载MTK Meta VCOM0E8D:2000MTK官方驱动包基带调试、META工具MTK USB Debug Port0E8D:0001/0002MTK官方驱动包LK阶段调试这些PID的具体值在不同平台分支会有差异但VID_0E8D这个前缀不变识别MTK设备主要靠它。3.2 MTK驱动包里到底是什么在起作用网上很多“MTK驱动下载”的资源包解压后能看到一个inf文件和一个sys文件。inf是文本文件里面最关键的就是硬件ID匹配规则比如[Manufacturer] %MfgName%MTK,NTamd64 [MTK.NTamd64] %USB\VID_0E8DPID_0003.DeviceDesc%MTK_PORT, USB\VID_0E8DPID_0003装驱动时Windows读取inf发现USB设备的硬件ID是USB\VID_0E8DPID_0003就把它绑定到usbser.sys这个微软通用串行驱动上。mdmcpq.inf是Windows自带的一个调制解调器/串行设备安装文件MTK的inf通常会Includemdmcpq.inf来复用系统默认的串口安装逻辑。所以从架构上看MTK官方驱动并没有实现什么复杂的内核逻辑核心就是告诉Windows“这个设备是标准串口交给usbser.sys处理”。这一点和CH340驱完全不同CH340是必须加载厂商自己的内核驱动MTK走的是微软的通用串口栈。3.3 安装失败和签名问题的处理链路Win10、Win11强制驱动签名很多网上下载的修改版inf没有合法签名装的时候会提示“哈希不存在于指定目录”或者直接拒绝安装。遇到这种情况常规做法是打开“设置 → 系统 → 恢复 → 高级启动”重启进入修复模式依次选择“疑难解答 → 高级选项 → 启动设置 → 重启”在启动设置界面按数字键“7”或者F7选择“禁用驱动程序强制签名”系统启动后再执行inf右键安装一般就能装上。装好驱动后如果设备管理器里还是显示未知设备右键查看属性切到“详细信息”选项卡把硬件ID发出来确认是不是USB\VID_0E8D开头。如果不是说明设备根本没进入MTK下载模式这时的问题是触发方式不对不是驱动问题。还有一个很容易混淆的情况手机Android系统已经正常启动的情况下插USB设备管理器里看到的是“Android Composite ADB Interface”不是MTK VCOM。只有关机、让芯片进入BROM/Preloader下载阶段才会出现VCOM口。很多新手把ADB口当成VCOM口装半天驱动没反应原因就在这。Linux主机侧就简单很多内核直接加载cdc_acm模块就能识别MTK VCOM不需要装任何MTK驱动插上后内核日志会出现ttyACM0。这反过来也印证了一个结论MTK VCOM本质上就是标准CDC ACM设备。4. 刷机链路深潜从BROM枚举到SP Flash Tool识别之间发生了什么4.1 BROM为什么没有内核参与MTK芯片上电后第一个执行的是芯片内部固化的BootROM代码这代码写在芯片硅片里断电不丢失也不受OEM修改影响。它的任务非常狭窄初始化最基本的时钟、SRAM、USB物理层然后尝试在USB上枚举出一个设备等着PC通过这个通道把一段受信任的代码发进来。注意这时候DDR还没初始化Flash驱动也没加载内核连影子都没有。BROM只把自己当成一个“USB bootloader”不能干别的。PC端刷机工具比如SP Flash Tool向BROM发送的第一个协议包本质是“下载DA”。DA是Download Agent的缩写是一段由刷机工具携带的小程序被发送到芯片SRAM里执行。DA一旦跑起来就接管了后续和PC的通信负责初始化内存、读Flash、刷分区直接把BROM干掉的活接下来。所以刷机过程中VCOM口会断连重连就是因为BROM阶段结束后DA阶段又重新枚举了一次USB设备。如果PC驱动匹配不及时或者USB hub响应慢SP Flash Tool就会报连接失败。4.2 Preloader、LK、Kernel三阶段的VCOM重连完整的启动链路是BROM → Preloader → LK → Kernel → Android系统。每个阶段USB枚举的身份都不同阶段谁在跑设备管理器表现能否用于刷机BROM芯片内部固化代码MediaTek PreLoader USB VCOM_Port可以刷机工具最常用的入口PreloaderBROM加载到SRAMVCOM可能消失又出现PID可能变可以Flash Tool会识别LKPreloader加载到DRAM可能出现MTK USB Debug Port可以进fastboot类命令KernelAndroid内核ADB Interface、MTP、VCOM已经不是传统刷机通道实际维修时如果Flash Tool已经连上并开始加载DA但进度条卡住重新插拔后端口从PreLoader VCOM变成另一种设备不要去手动刷新驱动让驱动装完让Flash Tool自己重连一般都能继续。4.3 排查实录“MTK刷机连接BROM失败”最常见的5个原因“mtk刷机连接brom失败”是维修圈子里搜烂了的问题我测试过的真实原因是这些按排查顺序排驱动没生效或没装上。设备管理器里根本没有VCOM口那驱动就是没配对。先确认硬件ID再装对应inf。线材问题。很多Type-C数据线只支持充电D/D-线没接好或质量很差。换一根短一点的USB 2.0线插电脑主机后置USB口避开前置面板和hub。触发下载模式的方式不对。不是所有设备关机插上就自动进BROM有些需要按住某个按键或短接触发点后再插USB不同板子方式不一样要看对应硬件手册。盲目短接测试点风险很大不建议乱试。SP Flash Tool版本和DA不匹配。老版本工具不识别新平台芯片DA校验不过会被BROM拒载。换和芯片平台对应的新版工具。USB供电不足。笔记本的Type-C口在电池模式下供电不稳BROM枚举成功但数据传输时崩。优先用供电稳定的USB口或者给目标主板单独供电。还有一个容易忽略的Flash Tool没有以管理员身份运行。Win10以上UAC限制文件访问权限工具读不到DA文件时也会报BROM连接失败。4.4 为什么线序和供电影响那么大BROM枚举是在芯片最“脆弱”的阶段完成的此时时钟和电源都还没优化到位USB信号的抖动都比正常系统运行时敏感。USB线的阻抗不匹配、线材过长、接口氧化都会导致枚举不稳定。我自己的习惯是先不打开Flash Tool插上设备看设备管理器里的端口出现又消失是否规律。如果端口出现后能稳定停留几秒再开Flash Tool连如果端口一闪而过说明枚举都没稳定这时候调Flash Tool内的参数没有意义先解决线材和供电。5. 源码向如何定制一版属于自己的MTK VCOM驱动行为5.1 修改设备端枚举字符串和序列号手头有MTK内核源码想给VCOM改一个识别名可以从f_serial.c或f_acm.c里修改字符串描述符。核心是维护好usb_string数组和strings结构体改iManufacturer、iProduct、iSerial。如果是走configfs动态配置的开发板不需要重新编译内核直接在运行时改cd /config/usb_gadget/g1 echo 0x0E8D idVendor echo 0x0003 idProduct mkdir -p strings/0x409 echo MTK-LAB strings/0x409/manufacturer echo Virtual COM strings/0x409/product echo 1234567890 strings/0x409/serialnumber mkdir -p functions/acm.0 mkdir -p configs/c.1 ln -s functions/acm.0 configs/c.1 echo 1 UDC前提是内核开启了USB gadget configfs并且UDC控制器已经存在。量产MTK手机的内核不一定开这个功能但很多公版开发板和评估板是开的。5.2 主机端自定义INF的匹配规则主机端的inf编辑也很有用尤其是做产线工具想让设备显示成自己定义的名字。最简的inf长这样[Version] Signature $Windows NT$ Class Ports ClassGuid {4D36E978-E325-11CE-BFC1-08002BE10318} Provider %ProviderName% [Manufacturer] %ProviderName%DeviceList,NTamd64 [DeviceList.NTamd64] MTK VCOM CustomUSB_Install, USB\VID_0E8DPID_0003 [USB_Install] Includemdmcpq.inf,usb.inf Servicesusbser [USB_Install.Services] AddServiceusbser,0x00000002,USB_Install.Service [USB_Install.Service] DisplayName%Serial% ServiceType1 StartType3这个inf指定硬件ID是USB\VID_0E8DPID_0003服务使用usbser。注意ClassGuid必须是Ports类否则设备管理器里不会出现在“端口 (COM 和 LPT)”分类下。自签驱动或禁用签名后安装适合内部工具使用。5.3 没有MTK完整源码时怎么抓枚举描述符很多做PC侧工具的人拿不到MTK完整内核源码但依然可以分析VCOM枚举行为。用USBlyzer或者Wireshark加USBPcap抓包能看到完整的设备描述符、配置描述符、接口描述符。看到bInterfaceClass0x02CDC、bInterfaceSubClass0x02ACM、bInterfaceProtocol0x01基本就确定是标准CDC ACM所有后续的串口通信逻辑都可以按标准串口来做。如果抓包发现设备枚举出来的是复合设备带ADB接口和MTP接口那说明系统已经进入Android阶段VCOM已不在当前USB配置里这时候应该检查是否真的让芯片进入了下载模式。5.4 一个最小实验在Linux主机上端到端验证VCOM我想特别推荐一个验证方法做源码和工具开发的人大概率用得上。在Linux主机上先modprobe cdc_acm插入处于BROM阶段的MTK设备dmesg | grep tty看有没有出现ttyACM0用Python的pyserial就是普通串口操作import serial ser serial.Serial(/dev/ttyACM0, 115200, timeout1) ser.write(b\x40\x00\x00\x00) # 演示用具体协议包以刷机工具为准 data ser.read(16) print(data)这个实验能验证两件事一是MTK VCOM确实暴露成了标准tty设备任何看惯了串口的人都能操作二是你后续写PC端刷机/调试工具时完全不需要特殊API走普通串口读写就行。至于BROM私有协议的具体格式要配合官方DA才能完整往返不是一段简单串口脚本能搞定的。6. 驱动源码的知识地图从VCOM出发怎么读MTK平台其他驱动源码6.1 VCOM只是MTK驱动家族的一个角落VCOM只是MTK平台驱动源码里的一小块。它的邻居很多每个你都可能在项目里碰到drivers/usb/gadget/function/—— VCOM、MTP、ADB相关drivers/misc/mediatek/usb20/—— MTK私有USB控制器驱动sound/soc/mediatek/—— 音频DSP、codec驱动mtk平台耳机输出挂外置功放、双喇叭这类需求就是在这块改drivers/media/platform/mtk-isp/—— camera相关mtk camera的pipeline基本都在这drivers/power/supply/—— 充电、电量计驱动这些驱动风格差别很大但读法有共性。比如mtk camera涉及ISP、传感器、图像流数据通路比VCOM复杂得多mtk双喇叭的音频驱动则涉及DSP配置和时序控制。但不管哪个都是“板级配置 控制器驱动 功能驱动 数据通路”这个四元组。6.2 一套通用的读源码三板斧我从VCOM源码里提炼出来一套通用读法试过在mtk_uart、mtk_audio、mtk_camera这些驱动上都成立先看dts。找到对应节点看status是否okay、compatible是否匹配驱动里的of_match_table再看probe函数。看驱动入口做了什么注册了哪些cdev、tty_driver、platform_driver最后看数据通路。找到用户态能碰到的符号比如/dev/ttyGS0从open/write/read一层层往里追看数据从哪里来、到哪里去。这套方法把“读源码”从玄学变成工程流程。尤其对新手与其抱着一个几千行的驱动从头到尾读不如先按三板斧定位关键函数再展开细节。6.3 和VCOM打过交道的个人体会说点真话。我在产线联调时最崩溃的不是源码而是几十台设备同时插USB引发的枚举混乱。后来养成的习惯是先单台设备跑通完整链路再批量验证。批量验证时用质量好的USB hub千万别用机房淘汰下来的旧hub信号质量差到怀疑人生。另一个经验是驱动版本要跟着SP Flash Tool版本走。新旧驱动混用可能当前系统认为驱动没问题但Flash Tool就是识别不到端口重新装一次官方配套驱动就好。曾经为了一个“不稳定复现”的BROM连接失败问题折腾了两天最后发现是驱动版本太旧Firmware和DA都换了驱动还在用三年前的。所以如果你也卡在VCOM相关的问题上先按“硬件枚举是否稳定 → 驱动是否匹配 → 工具版本是否配套”这个顺序排查比直接去翻源码有效得多。源码是用来理解机制和做定制的大部分连接问题其实是处理链路上的环节没对齐。本文还有配套的精品资源点击获取