Type-C接口调试:一文读懂USB Billboard设备与Alt Mode协商失败
如果你做过 Type-C 接口方案的调试大概率遇到过这种让人血压上升的场景手里一根全新的 USB-C 转 DP 线缆插上“电脑 外接显示器”之后屏幕死活不亮或者是一个 Type-C Dock 接上之后视频信号完全没有但充电是正常的。更奇妙的是此时 Windows 右下角有时会弹出一条看上去有点“没头没尾”的通知提示你有一个“USB Billboard 设备”。很多工程师第一次看到 Billboard 这个词是在设备管理器里某个带黄色感叹号的节点上。乍一看它像个故障设备实际上它恰恰是“故障之后来传话的人”。这篇文章我会把 Billboard Device Class 的来龙去脉讲清楚包括它和 Alternate Mode 协商的关系、Billboard 描述符到底长什么样、在哪些失败场景下会被触发以及我在实际项目里踩过的坑和抓包经验。如果你正在做 Type-C 相关的固件、硬件或者系统集成这篇文章应该能帮你省下不少查资料的时间。1. 先从一个让人抓狂的场景说起1.1 一根“看起来没问题”的 Type-C 转 DP 线我印象很深的一次经历是帮朋友看一套 Type-C Dock 投屏问题。设备是某品牌的扩展坞支持 HDMI、DP、USB 3.0、PD 充电规格看起来非常齐全。结果接到笔记本上之后USB 外设都正常PD 充电也正常唯独 DP 口外接显示器没有任何反应。第一反应是“是不是 DP 线坏了”换了一根也一样。又怀疑是显示器的输入源没切对折腾了一圈最后在 Windows 设备管理器里看到一个陌生的设备节点“USB Billboard Device”。那一刻我才想起来Type-C 的 Alternate Mode 协商可能失败了而这个 Billboard 设备就是来告诉我失败原因的。这种场景并不少见。Type-C 的物理接口虽然统一了但它的能力矩阵非常复杂有的口只支持充电有的口支持 USB 2.0 数据有的口支持 USB 3.x 数据有的口支持 DP Alt Mode、Thunderbolt Alt Mode。插入之后两端到底能不能进入某个 Alternate Mode完全取决于一次“看不见的协商”。1.2 设备管理器里的“陌生来客”对于普通用户来说当视频没有输出时看到右下角弹出一个“设备可能无法正常工作”的通知第一反应往往是“这个设备是不是坏了”。但从协议栈的角度看Billboard 设备并不是故障设备它更像是一张“病历单”。如果没有 BillboardAlt Mode 协商失败之后主机端和用户都只能面对一个“黑屏”或“无信号”的结果完全不知道该怪线缆、怪显示器、怪接口还是怪系统设置。有了 Billboard 之后设备可以继续在 USB 总线上以标准 USB 设备的方式完成枚举然后把协商失败的状态、原因、甚至一个帮助链接通过描述符和字符串上报给操作系统。操作系统再把它转成一条用户能看懂的通知。1.3 USB-IF 定义 Billboard Class 的初衷USB-IF 推出 Type-C 标准时Alternate Mode 是最大的卖点之一。一个接口既能传 USB 数据又能输出 DisplayPort 或 Thunderbolt 信号确实很吸引人。但这也带来了一个体验问题USB 数据传不了、视频也黑屏时用户根本不知道问题出在哪。Billboard Device Class 规范就是在这样的背景下出现的。它的设计目标非常简单协商失败时设备通过一个标准的、人类可读的方式把状态告诉主机。规范里定义了一套能力描述符、字符串描述符、HID 报告结构让操作系统可以识别“这是一个 Billboard 设备”并且读取设备提供的错误说明。理解了它产生的背景后面看描述符和协议细节就会顺很多。它不是一个用来传大数据的功能类而是一个纯粹的“状态广播”机制。2. Alternate Mode 协商流程从 CC 线上的握手到 SBU 上的数据2.1 Type-C 引脚与 CC 通道的关系要理解 Billboard 为什么存在得先搞清楚 Alternate Mode 的协商是怎么走的。Type-C 接口一共有 24 个引脚除了大家都熟悉的 VBUS、GND、D/D- 和 4 对超高速差分线之外还有两组经常被忽略的引脚CC1/CC2 和 SBU1/SBU2。CC 引脚Configuration Channel是整个 Type-C 生态的“神经中枢”。它负责的事情非常多检测正反插方向确定设备是 Source供电方还是 Sink受电方在 USB Power Delivery 中充当通信链路承载 PD 报文通过 eMarker 芯片读取线缆能力Alternate Mode 的 VDMVendor Defined Message厂商自定义消息协商就是跑在 CC 上的 PD 通信里的一种消息类型。而一旦协商成功真正传视频信号的是超高速差分线和 SBU 引脚。拿 DisplayPort Alt Mode 举例它会借用四对超高速线中的两对或全部四对来传输 DP 的差分信号而 SBU1/SBU2 则被复用成 DP Auxiliary Channel 的 AUX/AUX-。2.2 VDM 协商的四步PD 协议里进入 Alternate Mode 的 VDM 协商本质上是 Source通常是电脑或扩展坞和 Sink通常是显示器或线缆另一端的设备“对话”的过程。我把这四步用大白话翻译了一下第一步你怎么称呼自己Discover SVIDsSource 发送 Discover SVIDs 命令问 Sink“你支持哪些厂商定义的 Alt Mode把 SVID 列表报上来。”SVID 是 16 位的唯一标识比如 VESA 给 DisplayPort Alt Mode 分配的 SVID 是 0xFF01Intel 给 Thunderbolt 分配的 SVID 是 0x8087。第二步你支持哪种姿势Discover ModesSource 拿到 SVID 列表以后会针对某个具体 SVID 发 Discover Modes 命令比如“你支持 DP 的哪个版本支持几通道支持哪种引脚分配”Sink 回复的 Mode 值实际上是一组位图每一位代表一个 Mode 编号。第三步就按这个姿势来吧Enter ModeSource 选定一个 Mode发送 Enter Mode 命令。如果 Sink 回复 ACK表示双方达成一致SBU 和高频线开始切换到 Alt Mode 信号。如果 Sink 回复 NAK、BUSY 或者干脆超时协商失败。第四步结束这个模式Exit Mode / 超时正常断开或遇到异常时Source 或 Sink 可以发送 Exit Mode 命令退出特定模式。但如果协商压根就没成功这一步自然也不会发生。需要强调的是这些 VDM 报文都封装在 USB PD 协议的 SOP* 报文里传输速率不高BMC 编码经典速度是 300 kbps 到 1 Mbps 级别但足够承载协商数据了。Alt Mode 协商的“信号质量”和“视频数据速率”基本没什么关系——它只负责“握手”。2.3 协商失败的各坏点根据我的实际经验Alt Mode 协商失败可以发生在好几个环节而且表现各不相同失败环节可能原因典型表现CC 物理连接异常劣质线缆没有接 CC或者接触不良连 PD 都不能协商设备完全不识别eMarker 能力不足线缆 eMarker 没有声明支持 SBU/Alt ModeSource 不会发起 Discover ModesDiscover Modes 无响应Sink 固件不支持该命令进入超时协商卡在第二步Enter Mode NAKSink 不支持选定的 Mode 或资源不足第四步直接被拒SBU 信号链路异常线缆的 SBU 线未连接或断开即使 Enter Mode 成功显示器依然黑屏HPD 事件未触发DP 接收端没有拉高 Hot Plug Detect显卡认为没有接显示器这张表想说明一个核心问题“接入 Type-C 口”和“Alt Mode 真正建立成功”之间隔着很多道关卡任何一道关卡失败用户看到的就是黑屏或不识别。而 Billboard 设备能做的就是在这个链条的末端给主机提供一个可读的失败线索。2.4 为什么协商失败会导致“提示都没一个”很多用户不理解视频输出失败为什么系统不弹一个“显示器连接失败”的提示原因在于DP Alt Mode 协商成功之前显卡和显示控制器完全不知道外面接了一个显示器。DisplayPort 的热插拔检测是靠 HPD 信号驱动的而 HPD 走的是 DP 的 AUX 通道也就是 Type-C 的 SBU 引脚。只有 Enter Mode 成功、SBU 切换到 AUX 之后显卡才能感知到显示器存在。所以一旦协商失败显卡层面的结果就是“没有显示器连接”自然不会有任何正常提示。这时候 Billboard 就是唯一的“吹哨人”。它不依赖 DP 链路而是作为一个标准的 USB 设备出现在主机总线上绕开了整个视频链路。3. Billboard 设备的内在机制如何把“协商失败”翻译成人话3.1 Billboard 在 USB 协议栈中的位置从 USB 规范的角度看Billboard Device Class 的设备类别代码是 0x11。你可以在设备的 Device Descriptor 的 bDeviceClass 字段里看到这个值也可以在复合设备的某个接口描述符里看到它。不过现实中的实现比规范更灵活。一套 Type-C Dock 通常包含 USB Hub、USB 音频、USB 以太网等多个功能Billboard 往往是其中一个接口。设备描述符的 bDeviceClass 可能会被设为 0xEFMiscellaneous混合设备表示它是一堆接口的集合而具体的 Billboard 功能由某个接口描述符来表示。最常见的实现方式是用一个 HID 接口来承载 Billboard 的状态报告。选 HID 的原因很简单HID 类在操作系统里有天然支持不需要额外装驱动HID 的 Report Descriptor 结构非常适合传一小段状态数据字符串描述符和 HID 报告可以很好地配合3.2 BOS 里的平台能力描述符Billboard 设备有一个非常关键的描述符藏在 BOSBinary Device Object Store里叫做 Billboard Capability Descriptor。BOS 描述符是 USB 3.0 时代引入的结构用来描述设备的一些扩展能力。Billboard 能力以一种“Platform Capability Descriptor”的形式存在其中 bDevCapabilityType 0x05代表 Platform Capability。我可以贴一段典型的结构字段含义特别直观字段长度值/说明bLength1描述符长度通常为 28bDescriptorType10x10Device CapabilitybDevCapabilityType10x05Platform CapabilitybReserved1保留置 0PlatformCapabilityUUID16Billboard 的 UUIDUSB-IF 定义bcdVersion2Billboard 规范版本如 0x0100bVendorCode1用于访问 Billboard 特定功能的厂商请求代码iLandingPage1一个字符串描述符索引指向“关于这个产品/如何解决的问题”的说明bConnection1当前的连接状态比如 0 表示非活动1 表示活动bAltMode1当前试图进入的 Alt Mode 编号0xFF 可能表示无bAlternateHBR / bAlternateHR / bAlternateRR3一些高比特率、音频、保留的额外状态标志PlatformCapabilityUUID 是识别 Billboard 能力的关键。USB-IF 定义的 UUID 是C8C9B500-DFF9-4D2B-9770-684B4DEE42AF。在描述符里UUID 的字节序需要按规范要求填充这一点在自研固件时特别容易踩坑后文会细说。3.3 字符串描述符与 HID 报告的配合从使用者的视角看最有价值的信息其实是 iLandingPage 指向的那条字符串。这条字符串通常包含设备名称、厂商信息和型号支持的 Alt Mode 类型比如 DP、Thunderbolt一句类似“该设备需要通过支持 DisplayPort Alternate Mode 的线缆/接口才能正常显示”的帮助文本或者一个厂商官网链接操作系统驱动拿到 iLandingPage 索引后会发起标准 USB 的 GET_DESCRIPTOR(String) 请求把这段文本读出来显示给用户。HID 接口则负责动态状态。Billboard 的 HID 报告里包含一组精简的状态字段比如 bConnection、bAltMode、bAlternateHBR 等。主机可以通过 HID 的 GET_REPORT 请求拉取当前状态也可以通过中断 IN 端点接收主动上报。固件可以在协商失败后更新这些状态再通过 HID 主动通知主机。3.4 操作系统如何消费 Billboard 信息不同操作系统对 Billboard 的处理方式差异挺大的Windows识别到 Billboard 后加载 usbbillboard.sys 或通用 HidUsb 驱动然后从描述符里读取状态和字符串最后在系统托盘中显示通知。这也是我在文章开头那个场景里莫名其妙看到一条提示的原因。macOS对 Billboard 的支持相对有限部分版本能够识别设备但不会主动弹完整帮助信息。Linux内核的 USB 核心没有专门为 Billboard 写一套用户态通知逻辑但 sysfs 和 lsusb 都能完整暴露 BOS 描述符开发者可以通过 usbhid-dump 或写个小脚本读取状态。对使用者来说Windows 算是对 Billboard 利用得最充分的操作系统。这也是为什么很多 Type-C 测试文档都会建议“在 Windows 环境下验证 Billboard 功能”。4. 实测一次真实的 DP Alt Mode 协商失败与 Billboard 数据解读4.1 测试环境与工具纸上谈兵没意思。我实际做过的测试里有一次很典型某款 Type-C DockDP Alt Mode 协商失败Windows 弹了 Billboard 通知。我当时的测试环境一台 Windows 11 笔记本USB4 口一台 Type-C Dock支持 PD、HDMI、DP外接显示器用 DP 线连接工具USBView、Wireshark USBPcap、lsusb通过 WSL/独立 Linux 机器观察同一台 Dock需要说明的是如果要在 Windows 上抓 USB 枚举过程USBPcap 是成本最低的方案。USBView 则能直接看到当前总线上的设备树和描述符。4.2 从枚举数据中识别 Billboard 设备把 Dock 接上后USB 总线里出现的设备不止一个。我在 USBView 里看到的拓扑大致是根 HubType-C Dock 内部的 USB 3.1 Hub下游USB 以太网下游USB 音频下游无人识别的 HID 设备这就是 Billboard这个 HID 设备的描述符里bInterfaceClass 0x03HID厂商 Product 字符串写着类似“USB Billboard”的字样。进一步看 BOS 描述符能看到一个 Platform Capability Descriptor里面的 UUID 正是 Billboard 的 UUID。如果你是在 Linux 下一条命令就能确认lsusb -t lsusb -v -d 0451:ace1这里的-v会打印包括 BOS 在内的所有描述符。你可以直接搜 “Billboard” 关键字看到类似下面的输出Platform Capability Descriptor: bLength 28 bDescriptorType 16 bDevCapabilityType 5 bReserved 0 PlatformCapabilityUUID C8C9B500-DFF9-4D2B-9770-684B4DEE42AF bcdVersion 1.00 bVendorCode 1 iLandingPage 6 bConnection 0 bAltMode 0xff这个片段基本就说明问题了iLandingPage 指向字符串描述符索引 6bAltMode 是 0xFF表示当前不处于任何 Alt Mode。4.3 从描述符读懂失败原因接着我通过 USBView 的字符串表查看 iLandingPage 索引对应的内容是一段人类可读的文本大意是“设备需要通过支持 DisplayPort Alternate Mode 的线缆和端口才能显示。请确认你使用的线缆支持 DP Alt Mode。”实际哪家厂商的文案我这里就不公开了但结构都是一致的。字符串描述符里往往会给出两个信息一是“发生了什么”二是“用户该怎么做”。这两个信息对于售后支持的意义非常大至少用户不用再靠猜。在 Windows 的事件查看器里如果开启了 USB 相关日志也能看到类似 “The USB device ... has encountered an error and cannot communicate properly” 的记录。注意这里的“cannot communicate”不是说 USB 枚举失败而是说 Alt Mode 协商失败。4.4 对照 PD 抓包还原真相要想看到 Billboard 背后的“真相”还需要抓 CC 线上的 PD 报文。普通 USB 抓包工具只能看到 USB 总线上的枚举和数据传输看不到 CC 线上的 VDM。我用的是逻辑分析仪配合 PD 解码器直接跨在 CC1/CC2 上抓。回放数据能看到这样的时序Source 发送 Discover SVIDsSink 回复 SVID 列表0xFF01DP Alt ModeSource 发送 Discover ModesSink 回复 DP Mode 1/2/3Source 选定 Mode 3发送 Enter ModeSink 没有回复 ACK超时超时之后固件立刻在 USB 侧更新了 Billboard 状态。也就是说整个失败链路是PD 协商超时 - Dock 固件标记协商失败 - USB 枚举时把失败状态写入 Billboard 描述符 - Windows 读取后弹出通知。如果不抓 PD你只能看到 Billboard 的结果结合 PD 抓包才能确定根因在 Sink 无响应。5. 做过几个项目之后总结的坑与经验5.1 描述符字节序和 bVendorCode 配置第一个坑就是 UUID 的字节序。Billboard 的 PlatformCapabilityUUID在规范文档里写的是C8C9B500-DFF9-4D2B-9770-684B4DEE42AF但在实际填充进描述符时前三个域是按小端序存的。也就是说你直接照抄字符串里的顺序是不对的要先把 C8C9B500 变成 00 B5 C9 C8把 DFF9 变成 F9 DF4D2B 变成 2B 4D后面 9770 和 684B4DEE42AF 照抄。我见过不止一次工程师把 UUID 的字节序搞反结果系统的 Billboard 识别层根本认不出设备。这个坑在 USB 标准里非常典型不只是 Billboard几乎所有 Platform Capability Descriptor 都要注意字节序。bVendorCode 也很容易被人忽略。它表示“厂商自定义请求”的 bRequest 值。如果固件定义了 bVendorCode0x01那主机就能用这个代码发起厂商请求去读取一些额外状态。不要把它随便设成 0x00在某些操作系统中会被视为保留值。5.2 复合设备中接口描述符易出错第二个坑出现在复合设备Composite Device的场景。Dock 往往同时有 USB Hub、音频、网络、Billboard 这些功能如果设备描述符里用了 IADInterface Association Descriptor来组合多个接口那么 IAD 的 bFirstInterface 和 bInterfaceCount 一旦填错整个设备在 Windows 里会变成“ Unknown USB Device (Device Descriptor Request Failed)”。我建议在没有必要时把 Billboard 独立成一个单独的 HID 接口挂在 Hub 下游而不是和音频、网络抢同一个复合设备上下文。独立接口的好处是即使其他功能驱动异常Billboard 仍然能被操作系统枚举出来从而保留“最后一次传递信息”的能力。5.3 固件中何时触发 Billboard 报告很多固件开发者在写代码时会纠结到底在哪个时间点把 Billboard 状态置成“失败”我总结的实践经验是收到 Enter Mode 的 NAK 时立即记录失败原因Enter Mode 发送后超过 PD 协议规定的超时时间通常是 300ms 左右没有 ACK也记为失败从 Alt Mode 进入成功但后续 HPD 事件超时或 SBU AUX 握手失败同样可以作为失败场景上报要注意一点Billboard 状态往往是在枚举阶段就固定的。USB BOS 描述符在设备枚举之后一般不会动态变化如果你等枚举完成之后再想改 bAltMode主机不一定能及时感知。更稳的做法是固件内部维护一个“最近一次协商结果”的状态在下一次 USB 枚举时把该状态生成进 BOS 描述符和 HID 报告。5.4 Alt Mode 失败但不报 Billboard 的常见情况还有一类情况需要特别留意Alt Mode 协商失败但 Billboard 并没有弹出提示。常见原因如下线缆本身不带任何电子元件CC 上连 PD 都没有建立Sink 端点压根没有可枚举的 USB 控制器设备厂商没有实现 Billboard 功能只在固件里记录了一个日志用户插入的是一个只支持 USB 2.0 的 Type-C 口而 Billboard 功能只在 USB 3.x 枚举之后才暴露操作系统不支持该描述符结构比如部分老版本系统遇到这些情况时别一根筋地找 Billboard先确认一下整个链路里有没有一个“可以枚举 USB 的控制器”。如果连 DP 也不想传、USB Hub 也没工作那说明问题可能出在最基础的供电或 CC 探测上。5.5 好用的调试工具最后把工具清单列一下都是实际工程里高频使用的工具用途适用场景USBViewWindows SDK查看设备树、BOS 描述符最快捷确认 Billboard 能力Wireshark USBPcap抓 USB 枚举和控制传输分析描述符请求与响应时序lsusb -v / usbhid-dumpLinux查看 BOS、HID ReportLinux 下开发调试逻辑分析仪 PD 解码器抓 CC 线 VDM定位 Alt Mode 协商失败根因协议分析仪如 LeCroy/Total Phase抓 USB 侧信道分析复杂复合设备调试我个人最常用的组合是 Linux 下lsusb -v快速确认描述符再用逻辑分析仪抓 PD。没有逻辑分析仪的话也可以买一个带 PD 抓包功能的 Type-C 转接板成本不高但对定位问题帮助巨大。6. 关于 Billboard 这件事我的一些看法接触 Billboard 设备类这一年多我最大的感受是它不太起眼但在 Type-C 生态里的价值被严重低估了。Type-C 的最大问题是“物理统一”带来了“能力碎片化”用户无法从外观判断一根线、一个口、一台显示器到底支持哪些功能。Billboard 是当前唯一一个把这种能力碎片化的失败信息从协议层传递到用户层的标准机制。如果你正在做 Type-C Dock、转接头、显示器或线缆的产品定义我建议把 Billboard 功能当成必选项来做而不是可选项。它不复杂也不会消耗太多资源但在售后和用户体验层面它可能是用户唯一能看到的“诊断报告”。最后再分享一个小技巧在做兼容性测试时不要只在 Windows 下看 Billboard 通知。试着在 Linux 下把 BOS 描述符打出来对比不同系统对同一组描述符的解析差异。很多时候Windows 弹了通知说明描述符基本没问题但 Linux 下更容易暴露出字节序、索引越界这类细节错误。把这些错误提前修掉能省下后续大量的兼容性返工。