技术背景

我们的板子作为 USB Gadget 设备通过 USB 线接入 USB 主机使用,我们的板子被主机识别为一个 Compsite Device,这个 Compsite Device 是由我们板子根据 Host 口实际接的 USB 设备动态创建的,所以它包含哪些功能,由接在 Host 口的设备决定。假设我们的板的 USB Host 口接了一个键盘和一个鼠标,那个我们的板就会被主机识别为一个支持键盘和鼠标功能的 Compsite Device。我们板上 Host 口接的设备的数据会被转发给 USB 主机。

问题描述

某个鼠标接入我们板 USB Host 口后,我们板子使用此鼠标创建的 USB Gadget 设备无法被 Windows 系统枚举成功,异常现象为:

  1. 一个联想鼠标,接入我们板,我们板作 USB Gadget 接入 WIN10 系统后,系统无法识别,无法完成 USB 枚举过程
  2. 这个联想鼠标直接接在 WIN10 系统上,是能正常识别和工作的
  3. 这个联想鼠标接入 Ubuntu 系统,也是能正常识别和工作的

分析过程

从应用层程序入手,排除 USB 设备描述符与 HID 报文描述符设置等应用层问题,对比分析 Linux 与 Windows 系统 USB 枚举过程差异,跟踪 Linux 内核代码 configfs 驱动部分。

原因解析

Linux 系统在 USB 设枚举过程中获取到设备的实际 HID 报文描述符长度后,会使用此实际长度作为期望的长度,来获取 HID 报文描述符。而 WIN10 会使用实际长度另加上 64 作为期望长度来获取 HID 报文描述符。这是 Windows 系统和 Linux 系统的差异,这个差异会引起异常,而 WIN10 的这种处理机制也是符合 USB 规范的,所以此异常应该是 Linux 内核的一个 BUG。

主机端在获取 HID 报文描述符时如何判断设备端已经应答完毕是这个问题的关键。

控制传输中的最大包长:高速设备最大包长是 64 字节;低速设备是 8;全速设备可以是 8 或 16 或 32 或 64。最大包长表示一个端点单次接收/发送数据的能力,实际上就是该端点对应的缓冲区的大小。当一次传输的数据量超过该端点的最大包长时,需要将数据拆分成多个包传输,只有最后一个包可以小于最大包长,除最后一个包外的其他包都应等于最大包长。所以在一次控制传输中,如果一个端点收到/发送了一个长度小于最大包长的包,则表示此次数据传输结束。

在设备枚举阶段,传输类型是控制传输,最大包长由 MaxPacketSize 参数(对于 USB 2.0 设备此值是 64)指定。一次控制传输的数据会被切割成多个包,只有最后一个包的长度可以小于最大包长。当主机接收到的数据量已经等于期待数据长度时,直接就可以判定应答已经结束了。当主机接收的数据量小于期待数据长度时,若接收到的最新的应答数据包的长度小于最大包长,说明这个包是这次传输的最后一个包,表示应答已完毕;若最新收到的数据包等于最大包长,主机是无法判断这个包是不是本次传输的最后一个包的 ,USB 协议规定,针对这种情况,当设备端应答的数据量小于主机侧期待的数据长度,而应答数据量又刚好能被最大包长整除(即被切割成多个完整的包),就需要额外再发送一个 ZLP 包(Zero Length Packet)以指示本次传输完成。

异常的这个联想鼠标,它的 HID 报文描述符是 64 字节长(刚好等于 MaxPacketSize 参数),当 WIN10 系统以期望长度 128(64+64) 来获取 HID 报文描述符时,内核 Gadget 驱动只回复了实际的 64 个字节(它没有发 ZLP 包)的 HID 报文描述符,此时 Linux Gadget 认为自己已经应答完毕,而 WIN10 收到的回复不足 128 字节但最后一个包又是整包,它认为传输还没完成一直在等新数据,直到超时,总线进入异常状态,WIN10 复位 USB 总线,设备侧内核 USB 驱动模块进入错乱状态。原因就是,Linux Gadget 驱动在这种特殊情况下没发 ZLP 包。这就是问题描述中现象 1 的原因。

为什么这个鼠标接在 Ububtu 上又正常呢,因为 Ubuntu 期待的长度就是 64,收到 64 字节的应答,它就认为应答已经完毕。

解决方法

知道了原因就好解决了。修复内核 BUG,在 Gadget 的驱动代码里,判断当一次应答的数据量小于主机期待的长度且应答数据量又能被最大包长整除时,多发一个 ZLP 包。问题解决。

USB Gadget设备枚举失败的处理方法的更多相关文章

  1. 浅析USB之设备枚举

    当一个USB设备插入主机后,会有以下活动: 配上状态图

  2. Windows与自定义USB HID设备通信说明.

    1 .   所使用的典型 Windows API CreateFile ReadFile WriteFile 以下函数是 DDK 的内容: HidD_SetFeature HidD_GetFeatur ...

  3. C#:USB设备枚举 --转自CSDN作者:Splash

    (一)DeviceIoControl的PInvoke /* ---------------------------------------------------------- 文件名称:Device ...

  4. 控制器没有足够的带宽可利用为USB大容量存储设备的解决方法

    伴随网盘时代的没落,最近刚入手了一个移动硬盘.现在的移动硬盘都是USB3.0,传输速度比USB2.0要快很多.但是链接笔记本电脑后发现传输速度在20MB/s左右,跟USB2.0速度差不多,并不能达到传 ...

  5. 移动设备 小米2S不显示CD驱动器(H),便携设备,MTP,驱动USB Driver,MI2感叹号的解决方法

    小米2S不显示CD驱动器(H),便携设备,MTP,驱动USB Driver,MI2感叹号的解决方法 by:授客 QQ:1033553122 用户环境 操作系统:Win7 手机设备:小米2S   问题描 ...

  6. USB设备驱动之设备初始化(设备枚举)

    USB设备从接入HUB到正常工作之前.都属于设备枚举阶段.所谓设备枚举.就是让host控制器认识USB设备,并为其准备资源.建立好主机与设备间的数据传递机制. 该阶段的工作,是USB通信协议规定的,所 ...

  7. 弹出USB大容量存储设备时出问题的解决方法

    我的计算机->管理->系统工具->事件查看器->自定义视图->Kernel-Pnp->详情->进程ID 然后在任务管理器里找到该进程(任务管理器->查看 ...

  8. [未完] Linux 4.4 USB —— spiflash模拟usb大容量存储设备 调试记录 Gadget Mass Stroage

    linux 4.4 USB Gadget Mass Stroage 硬件平台: licheepi nano衍生 调试记录 驱动信息 │ This driver is a replacement for ...

  9. USB gadget 驱动 printer.c 分析

    1. modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 modprobe后面也可以加模块参数 2. prn_example从stdout获取数据然 ...

  10. Android USB gadget configfs学习笔记总结

    1.一个config_item 是通过显式用户空间mkdir操作创建的,通过rmdir销毁.属性(文件)在mkdir之后出现,可以通过read和write读取或修改属性文件.与sysfs一样,read ...

随机推荐

  1. 区块链特辑——solidity语言基础(一)

    Solidity语法基础学习 一.智能合约的结构: 首先以上是智能合约的结构,包含版权宣告.编译指示.Using for 宣告.错误定义.输入.列举与枚举.常数.合约.函数.注释.第一个注释不同于其他 ...

  2. 在IIS Express下部署NuGet私服

    用途 个人开发,部署自己的NuGet pkg. 环境 Win11 IIS Express (轻度使用,不安装IIS,而使用VS预装的IIS Express) VS2022 步骤 开发环境准备 因我拟用 ...

  3. Firebug Lite——在没有调试工具的浏览器(如IE6-7)中调试

    现在做前端的应该是蛮幸福的,现在主流的浏览器都自带了调试工具,如 Firefox Chrome IE8+ 等,方便了网页开发时的一些调试.但是类似IE6的调试还是非常的不方便.但是发现一个调试神器-- ...

  4. JBoltAI 与 AIGS 的深度融合:重构企业数智化未来

    在企业数智化转型浪潮中,JBoltAI 凭借其独特的 AIGS(AI Generate Service)解决方案,正成为连接大模型能力与企业实际需求的桥梁.其核心价值在于通过技术框架的重构,将 AI ...

  5. nodejs队列

    nodejs队列 创建具有指定并发性的队列对象.添加到队列的任务以并行方式处理(直到并发性限制).如果所有的worker都在进行中,任务就会排队,直到有一个worker可用.worker完成任务后,将 ...

  6. springboot+mongodb+jpa使用save()方法保存数据后id为0

    最近做mongodb版本升级,springboot版本从1.4.0.RELEASE升级到1.5.10.RELEASE后出现jpa使用save()方法保存数据后id为0的问题. 解决: 以下为原代码,使 ...

  7. 深度学习实战:从零构建图像分类API(Flask/FastAPI版)

    引言:AI时代的图像分类需求 在智能时代,图像分类技术已渗透到医疗影像分析.自动驾驶.工业质检等各个领域.作为开发者,掌握如何将深度学习模型封装为API服务,是实现技术落地的关键一步.本文将手把手教你 ...

  8. 说说 Java 的执行流程?

    Java 的执行流程 Java 的执行流程包括多个阶段,从源码编写到最终程序的执行,涉及到编译.类加载.字节码执行.垃圾回收等多个环节.下面将详细介绍 Java 程序的执行流程. 1. 编写源代码 开 ...

  9. 电脑ocr软件

    天若ocr 体积小,可以隐藏任务栏,但有时候识别度不好,停止更新了,新项目为树洞ocr github: https://github.com/AnyListen/tianruoocr/releases ...

  10. 【BUG】nuget restore遇到的两个报错“Failed to load msbuild Toolset”和“当前 .NET SDK 不支持将 .NET 6.0 设置为目标”

    出错环境: Visual Studio 2019 1. Failed to load msbuild Toolset 解决:https://github.com/NuGet/Home/issues/4 ...