技术背景

我们的板子作为 USB Gadget 设备通过 USB 线接入 USB 主机使用,我们的板子被主机识别为一个 Compsite Device,这个 Compsite Device 是由我们板子根据 Host 口实际接的 USB 设备动态创建的,所以它包含哪些功能,由接在 Host 口的设备决定。为方便描述,把这个 Compsite Device 称作 USB Gadget 设备。

当板子 Host 口上接的 USB 设备有变化时,比如拔掉一个键盘,或者新插入一个鼠标,这时 USB Gadget 设备都要被销毁重建,因为设备功能变化了。

问题描述

  1. 我们需要实现一个类似这样的功能:不插拔我们板子与电脑之前的 USB 连线,通过软件开关来实现相当于 USB 线插拔的功能,把我们板子与电脑用 USB 线提前连好,在我们板上执行一个连接,电脑上显示有新设备插入,再执行一下断开连接命令,电脑上显示设备被移除。为了方便,暂称这个功能为软插拔功能吧。

  2. 另外,发现一个问题,就是我们板子内创建的 USB Gadget 设备在销毁后,电脑侧无法感知到这个设备已被销毁,再次重新创建一个 USB Gadget 设备,电脑无法识别这个设备,设备枚举会失败。也就是 USB Gadget 设备无法重复创建,而它本身是需要动态创建的。

最后分析发现,上述这两点,实际是由同一个原因引起的。

分析过程

研究电脑对 USB 线的插拔检测机制,研究我们板上使用的 USB 控制器和 USB PHY 是否有寄存器等去配置来产生类似于 USB 线插拔的硬件行为。

原因解析

设备插拔的硬件检测机制:在 USB Hub 的每个下游端口的 D+ 和 D- 引脚上,分别接了一个 15K 的下拉电阻,当 USB Hub 下游端口未接设备时,因下拉电阻作用,D+ 和 D- 就是低电平。而在 USB 设备端,则在 D+ 或 D- 引脚上接了 1.5K 的上拉电阻。USB 1.1 和 USB 2.0 设备此上拉电阻是接在 D+ 上,USB 1.0 设备此上拉电阻是接在 D- 上。这样,当设备插入到 Hub 时,由 1.5K 的上拉电阻和 15K 的下拉电阻分压,其中一条信号线(D+ 或 D-)就会被拉高。HUB 检测到 D+ 或 D- 引脚上电平变换后,就知道有设备插入或移除。当 D+ 出现一个上升沿,表示新插入了一个 USB 1.1 或 USB 2.0 的设备,当 D- 出现一个上升沿,表示新插入了一个 USB 1.0 的设备;当 D+ 出现一个下降沿,表示拔除了一个 USB 1.1 或 USB 2.0 的设备,当 D- 出现一个下降沿,表示拔除了一个 USB 1.0 的设备。HUB 会将这个插拔信号上报到上游端口,Hub 层层上报,到达 Root Hub,Root Hub 上报给 USB 主机控制机,主机就检测到了插拔机制。

阅读 USB PHY 芯片手册,发现手册中有提供寄存器,可以控制 D+/D-上的上拉电阻打开或关闭,所以软插拔功能理论上是行得通的,之所以还有问题,应该是内核中 USB 驱动有 BUG。我们的 USB Gadget 设备是 USB 2.0 设备,插拔 USB 线时,应该在 D+ 上出现上升沿和下降沿,实测在销毁 USB Gadget 设备后,D+ 没有从高电平变为低电平,即 D+ 未能成功关闭上拉电阻。不能稳定地使能/禁止 D+ 脚上拉,就是USB Gadget 设备第二次创建后 PC 不能识别的原因,也是软插拔功能不工作的原因。

继续往下排查,找内核中偏硬件底层与上拉控制有关的代码痕迹,找到 gadget.c 中 dwc3_gadget_pullup(),这个函数嫌弃较大。仔细阅读代码,发现在 dwc3_gadget_soft_disconnect() 在 dwc3_gadget_soft_connect() 之前有一个 dwc3_gadget_soft_reset(),阅读我们板 USB 控制器的手册中 DCTL (USB3_XHCI) 寄存器的描述,提到 "Once DCTL.CSFRST bit is cleared, the software must wait at least 3 PHY clocks before accessing the PHY domain (synchronization delay). Waiting 5ms is long enough here. ",dwc3_gadget_soft_reset() 针对我们的 USB 控制器型号没有延时,在此函数中增加 5 ms 延时,问题解决。再用万用表测一下,销毁和重建 USB Gadget 设备时,D+ 可以按预期变化了,将 USB 接上电脑,功能也正常了。至此问题解决。

继续阅读下代码,发现 drivers/usb/gadget/udc/core.c 中内核通过 sysfs 接口向用户空间提供了connectdisconnect两个命令,这两个命令的实现在 soft_connect_store() 函数中,分别调用了两个函数:usb_gadget_connect() 和 usb_gadget_disconnect(),它们最终都是通过控制 D+/D- 的上拉电阻来实际设备与主机间的 connect 和 disconnect。所以 USB Gadget 的软插拔功能在内核中是有实现的,只是刚好在我们的硬件平台上有 BUG。

解决方法

问题描述中的两个问题实际是同一个原因引起。如原因分析中所述,在 dwc3_gadget_soft_reset() 中增加延时,这两个问题即解决。

参考资料

1. Windows环境下USB设备的插入检测机制

USB Gadget设备软插拔异常的处理方法的更多相关文章

  1. C# 查询所有设备的插拔事件

    private void test() { //Win32_DeviceChangeEvent  Win32_VolumeChangeEvent ManagementEventWatcher watc ...

  2. 2018-8-10-WPF-判断USB插拔

    title author date CreateTime categories WPF 判断USB插拔 lindexi 2018-08-10 19:16:53 +0800 2018-8-5 13:0: ...

  3. 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)

    在 .NET Framework 4.7 以前,WPF 程序的触摸处理是基于操作系统组件但又自成一套的,这其实也为其各种各样的触摸失效问题埋下了伏笔.再加上它出现得比较早,触摸失效问题也变得更加难以解 ...

  4. WPF 插拔触摸设备触摸失效

    原文:WPF 插拔触摸设备触摸失效 最近使用 WPF 程序,在不停插拔触摸设备会让 WPF 程序触摸失效.通过分析 WPF 源代码可以找到 WPF 触摸失效的原因. 在 Windows 会将所有的 H ...

  5. QTC++监控USB插拔

    #if defined(Q_OS_WIN) #include <qt_windows.h> #include <QtCore/qglobal.h> #include <d ...

  6. USB线插拔检测使用UEventObserver检测uevent事件的分析

    说实话这玩样儿的代码量真的很少,大家如果能耐得住性子啃一会儿也就能撸懂了. 在这之前研究USB线插拔的时候就知道了有这么个东西,当时也就看了看,但没做什么笔记.最近想用起来,却发现就只有个名字在记忆中 ...

  7. android6.0 外部存储设备插拔广播以及获取路径(U盘)【转】

    本文转载自:https://blog.csdn.net/zhouchengxi/article/details/53982222 这里我将U盘作为例子来说明解析. android4.1版本时U盘插拔时 ...

  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. C#.NET U盘插拔监控

    [1]涉及的知识点 1) windows消息处理函数 ? 1 protected override void WndProc(ref Message m) 捕获Message的系统硬件改变发出的系统消 ...

  10. ARM上的linux如何实现无线网卡的冷插拔和热插拔

    ARM上的linux如何实现无线网卡的冷插拔和热插拔 fulinux 凌云实验室 1. 冷插拔 如果在系统上电之前就将RT2070/RT3070芯片的无线网卡(以下简称wlan)插上,即冷插拔.我们通 ...

随机推荐

  1. 栈的应用(后进先出 LIFO)--括号匹配问题

    博客地址:https://www.cnblogs.com/zylyehuo/ # -*- coding: utf-8 -*- class Stack: def __init__(self): self ...

  2. Linux 系统出现异常排查思路

    16 系统出现异常排查思路16.1 查看用户信息16.1.1查看当前的用户# who 04:39:39 up  1:30,  1 user,  load average: 0.01, 0.01, 0. ...

  3. windows端5款mysql客户端工具

    1. MySQL Workbench 这属于mysql官方出品,免费,功能强大,是首选. 2. HeidiSQL 免费,功能强大,强烈推荐. 3. dbForge Studio for MySQL 收 ...

  4. maven知识理解和生命周期

    学习的技能/知识 运动 提升 不足 强化了maven的知识理解和生命周期 3公里日常跑,其中1公里破之前的记录达到3分40 没有赖床,嗯:写完的博客自己阅读又温习了一遍 下午没课,但都用来休息了.. ...

  5. [源码系列:手写spring] IOC第一节:简单bean容器

    本专栏带领大家手写一遍spring的核心代码,包括IOC,AOP,三级缓存... 第一节较为简单,后面的章节会逐渐提升代码量和复杂度,喜欢的同学记得订阅哦  ̄▽ ̄ 定义一个简单的bean容器BeanF ...

  6. 【Windows】如何关闭Windows10、Windows11自动更新

    如何关闭Windows10自动更新 零.问题 Windows10老是自动更新,有时候第二天起来又得重新打开软件,真麻烦,Win10自动更新的时候还有点卡. 如何关闭? 经过上网查询,发现完全关闭难度比 ...

  7. 新装ubuntu电脑的一些调整

    必要命令的安装 必要开发工具的安装 更换国内软件源 /etc/apt/sources.list文件,后面添加下面地址用来添加阿里源 deb http://mirrors.aliyun.com/ubun ...

  8. mybatis插入数据返回id的实现方式

    一. useGeneratedKeys="true" <insert id="saveUser" parameterType="com.apcs ...

  9. Eclipse 中 JAVA AWT相关包不提示问题(解决)

    原因: 由于在2021年7月15日 OpenJDK管理委员会全票通过批准成立由Phil Race担任初始负责人的 Client Libraries Group(客户端类库工作组). 新的工作组将继续赞 ...

  10. Robot Framework自定义库的创建于应用(全新库)

    场景:新建库文件,库文件内新增方法,用于robot调用执行原始方法内不具备的能力.具体方法图下 1.找到目录C:\Python27\Lib\site-packages 2.新增文件夹"New ...