01signal.com

在 Linux 上重置 USB 设备(并可能控制其电源)

介绍

在完美世界中, USB 设备和 hubs 表现良好,并设法解决他们遇到的任何问题。现实中会发生各种奇怪的事情,需要做点什么。常见的解决办法是拔掉 USB 插头,重新连接设备。但是,如果这需要自动发生怎么办?

最引人注目的解决方案出现在另一个网页上: 它会导致 USB hub的 drivers关闭并重新启动。效果几乎等同于断开并重新连接计算机上的所有 USB 设备。那是最重的锤子,有时是必要的。

本页介绍了两种重置特定 USB 设备的方法。我将首先介绍如何执行每种方法,并提供一些简单的解释。在此之后,我将介绍很多技术细节。

此处的整个讨论仅限于 Linux ,尽管此处介绍的第二种方法可能也适用于其他平台。

这里的很多信息都取自 Universal Serial Bus Specification Revision 2.0。此文档的文件名通常为 usb_20.pdf。

方法#1: 要求 Linux kernel 重置设备

有几种工具可用于执行此操作。最先进的工具是 usbutils的一部分。下载 usbreset.c 并将 gcc 用于其 compilation:

$ gcc -O3 -Wall -g usbreset.c -o usbreset

进而:

$ ./usbreset
Usage:
  usbreset PPPP:VVVV - reset by product and vendor id
  usbreset BBB/DDD   - reset by bus and device number
  usbreset "Product" - reset by product name

Devices:
  Number 001/004  ID 045e:07b2  Microsoft® Nano Transceiver v1.0
  Number 001/002  ID 04f3:0103
$ ./usbreset 001/004
Resetting Microsoft® Nano Transceiver v1.0 ... can't open [Permission denied]
$ sudo ./usbreset 001/004
Resetting Microsoft® Nano Transceiver v1.0 ... ok
$ sudo ./usbreset 045e:07b2
Resetting Microsoft® Nano Transceiver v1.0 ... ok

作为对重置的响应, kernel log中出现以下内容:

usb 1-6: reset full-speed USB device number 4 using xhci_hcd

本次会议展示的内容:

那么 usbreset 是做什么的呢?它归结为 USB 设备的 device file上的这个命令:

ioctl(fd, USBDEVFS_RESET, 0)

最后调用 kernel的 usb_reset_device()函数,它的作用远不止重置设备。这个想法是让整个过程顺利: 如果需要,此函数会通知设备的 driver 前后重置。它在重置前解除绑定 driver ,然后再绑定回去。设备的 configuration 也被重置后加载。没有这个,设备就不会知道它的 bus address ,也不会准备好进行任何数据交换。

所以这几乎就像重新连接设备一样,但没有要求它识别自己(因为信息已经知道)并且没有为它分配新地址。

对于 USB 3.x,这是效率较低的 hot reset。下面是关于 hot reset 的更多信息。

方法#2: 切换 USB port的 power state

也有多种工具可用于此目的。我将用 hubpower来演示这个方法。下载hubpower.c并执行 compilation:

$ gcc -O3 -Wall -g hubpower.c -o hubpower

使用此工具有点棘手,因为命令不会发送到 USB 设备本身。相反,请求被发送到 USB 设备连接到的 USB hub 。

所以第一步是弄清楚这是哪个 hub 。首先,让我们找到 USB 设备的地址:

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 045e:07b2 Microsoft Corp.
Bus 001 Device 002: ID 04f3:0103 Elan Microelectronics Corp. ActiveJet K-2024 Multimedia Keyboard
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

所以设备在 bus number 1 和 device number 4上。请注意,每次枚举 USB 设备时, device number 都会发生变化。

那么 USB 设备连接的是哪个 hub 呢?到哪个 port?

$ lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/6p, 5000M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
    |__ Port 6: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 6: Dev 4, If 1, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 6: Dev 4, If 2, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 11: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
    |__ Port 11: Dev 2, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M

所以设备号 4 连接到 port #6。 hub的 bus number 是 1,它的 device number 是 1(它是 motherboard的 USB controller,起到 root hub的作用)。

让我们看看 hubpower 对此有何评论:

$ sudo ./hubpower 1:1 status
Port  1 status: 0100  Power-On
Port  2 status: 0100  Power-On
Port  3 status: 0100  Power-On
Port  4 status: 0100  Power-On
Port  5 status: 0100  Power-On
Port  6 status: 0103  Power-On Enabled Connected
Port  7 status: 0100  Power-On
Port  8 status: 0100  Power-On
Port  9 status: 0100  Power-On
Port 10 status: 0100  Power-On
Port 11 status: 0303  Low-Speed Power-On Enabled Connected
Port 12 status: 0100  Power-On

注意“1:1”部分是 hub的 bus address。如果这是一个外接的 hub,那么每次 hub 连接到电脑时,这个 address 都会发生变化。

但是 ports 的数字永远不会改变(只要设备连接到同一个物理 port)。

现在,当我们知道设备的 port number时,让我们重置它:

$ sudo ./hubpower 1:1 power 6 off
Port  6 status: 0000  Power-Off
$ sudo ./hubpower 1:1 power 6 on
Port  6 status: 0100  Power-On

在第一个命令后,设备将在 kernel log中报告为断开连接:

usb 1-6: USB disconnect, device number 4

在第二个命令之后,计算机的行为就像设备已物理连接一样:

usb 1-6: new full-speed USB device number 5 using xhci_hcd
usb 1-6: New USB device found, idVendor=045e, idProduct=07b2, bcd Device= 7.04
usb 1-6: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-6: Product: Microsoft® Nano Transceiver v1.0
usb 1-6: Manufacturer: Microsoft
[ ... ]

因为这个 re-enumeration,给设备分配了一个新的 bus address :

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 045e:07b2 Microsoft Corp.
Bus 001 Device 002: ID 04f3:0103 Elan Microelectronics Corp. ActiveJet K-2024 Multimedia Keyboard
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

那么这就像物理断开 USB 设备并重新连接一样吗?答案或许是: 在大多数情况下, hubpower 命令不会真正关闭 USB 设备的电源。因此,该设备将继续接收其 VBUS voltage (5V)。很少有 USB hubs 真正关掉电源。更多关于下面的内容。

对于绝大多数 hubs,第一个命令(“关闭电源”)只会将 port 置于使其忽略设备的状态。第二个命令(“打开电源”)将 port 返回到其自然状态。结果是检测到设备,并开始其初始化过程。其中,设备被重置和枚举,其 driver 对其进行初始化。

因此,物理断开连接通常比这些命令更有效,尤其是当设备从 USB plug获得电源时。但如果 hub 真的关闭了 VBUS, hubpower 同样有效。

请注意,在此示例中,命令被发送到 motherboard的 USB controller ( root hub)。原因是 USB 设备直接连接到计算机。如果此设备通过外部 hub连接到计算机,则应将命令发送到此外部 hub。在这两种情况下, hubpower 的使用方式相同。

不幸的是,hubpower 不支持 USB 3.0 (SuperSpeed)。更多关于下面的内容。

两种方法的区别

那么第二种方法(使用 hubpower)与第一种方法(使用 usbreset)有何不同?为了解决设备问题,这两种方法本质上是相同的: 他们发送重置命令。发生这种情况的方式截然不同,但仍然是这个重置命令可能会解决问题(如果有的话)。

但是有一些重要的区别:

控制电气设备(?)

尽管本页的主题是如何解决 USB 设备的问题,但也有一个有趣的副作用: 有时可以控制 USB port的 5V power supply。换句话说,可以使用简单且便宜的 USB hub 打开和关闭能够处理 2.5 Watts的 power supply 。

这足以控制 electromechanical relay。所以只需要添加一个组件就可以控制一个运行在 110V / 220V上的电器。嗯,添加一个简单的二极管也是个好主意,以保护 USB hub 免受损坏。但仅此而已。

不幸的是,控制 power supply 的能力是可选的: 根据 USB 2.0 规范中的第 11.11 节,当 port 处于 Powered-Off 状态时, hub 可能具有将 5V power supply 关闭到 port 的 power switches 。或者,一个 power switch 可用于控制多个 ports (“ganged power switching”)的电源。控制电源的目的主要是为了关闭电流过大的 USB 设备,让剩余的 ports 继续正常工作。

但如前所述,物理电源控制是可选的。 hubpower 实际上所做的是更改 port的 PORT_POWER 属性的值(在 USB specifications中称为“feature”)。此更改涉及 hub的 port的两个不同方面:

下面对PORT_POWER 进行了更详细的解释。

我的 hub 是否控制电压?

您如何知道您的 hub 是否真的关闭了电压?唯一可以确定的方法是对其进行测试。连接任何不是 USB 设备但会消耗 USB port电源的设备。真正的 USB 设备可能会增加混乱。例如,光电鼠标通常会响应关机命令关闭其 LED ,即使 5V 电压仍然存在。

每个 hub 在“lsusb -v”可见的信息(在 Hub Descriptor中,在规范的第 11.23.2.1 节中定义)中声明它是否控制电压,以及控制到什么粒度。 hub 可能会声明它不控制电压,或者它控制 ports (“gangs”)组中的电压,或者它单独控制每个 port 的电压: 根据 USB 2.0 规范中的第 11.11 节,“a hub with power switches can switch power to all ports as a group/gang, to each port individually, or have an arbitrary number of gangs of one or more ports”。

不过,这个消息并不可靠。我遇到过几个 hubs 声称他们控制电压,但他们都没有。

例如,这是“lsusb -v”的输出

Bus 001 Device 073: ID 0bda:5411 Realtek Semiconductor Corp.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.10
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         2 TT per port
  bMaxPacketSize0        64
  idVendor           0x0bda Realtek Semiconductor Corp.
  idProduct          0x5411
  bcdDevice            1.23
  iManufacturer           1 Generic
  iProduct                2 4-Port USB 2.0 Hub
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:

[ ... ]

Hub Descriptor:
  bLength               9
  bDescriptorType      41
  nNbrPorts             4
  wHubCharacteristic 0x00a9
    Per-port power switching
    Per-port overcurrent protection
    TT think time 16 FS bits
    Port indicators
  bPwrOn2PwrGood        0 * 2 milli seconds
  bHubContrCurrent    100 milli Ampere
  DeviceRemovable    0x00
  PortPwrCtrlMask    0xff
 Hub Port Status:
   Port 1: 0000.0503 highspeed power enable connect
   Port 2: 0000.0503 highspeed power enable connect
   Port 3: 0000.0100 power
   Port 4: 0000.0100 power

看起来很乐观,不是吗?实际上,这个 hub 根本不控制电压。

相比之下,这是一块普通主板的 hub:

Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         1 Single TT
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0002 2.0 root hub
  bcdDevice            4.15
  iManufacturer           3 Linux 4.15.0-20-generic xhci-hcd
  iProduct                2 xHCI Host Controller
  iSerial                 1 0000:06:00.0
  bNumConfigurations      1
  Configuration Descriptor:

[ ... ]

Hub Descriptor:
  bLength               9
  bDescriptorType      41
  nNbrPorts             2
  wHubCharacteristic 0x000a
    No power switching (usb 1.0)
    Per-port overcurrent protection
    TT think time 8 FS bits
  bPwrOn2PwrGood       10 * 2 milli seconds
  bHubContrCurrent      0 milli Ampere
  DeviceRemovable    0x00
  PortPwrCtrlMask    0xff
 Hub Port Status:
   Port 1: 0000.0100 power
   Port 2: 0000.0100 power
Device Status:     0x0001
  Self Powered

所以这款 hub 承认不支持任何电压控制。

请注意,除了有关电源开关的信息外,还有有关每个 port 的状态信息,如“Hub Port Status”。这些 status bits 在 USB 2.0 规范(第 11.24.2.7.1 节)的表 11-21 中定义。这与 hubpower获取的信息相同。

uhubctl 工具

用 USB hub 控制 relay 的想法是许多计划的动机。 uhubctl值得一看,主要是因为该项目维护了一个控制电压的 USB hubs 列表。

该工具显然仅用于电压控制,而不用于解决 USB 设备的问题。例如,默认情况下, uhubctl 会忽略未声明能够为每个 port单独控制电压的 hubs 。

这些命令等同于上面的 hubpower 命令:

$ sudo ./uhubctl -f -l 1 -p 6 -a 0
Current status for hub 1 [1d6b:0002 Linux 5.16.0 xhci-hcd xHCI Host Controller 0000:00:14.0, USB 2.00, 12 ports, nops]
  Port 6: 0103 power enable connect [045e:07b2 Microsoft Microsoft? Nano Transceiver v1.0]
Sent power off request
New status for hub 1 [1d6b:0002 Linux 5.16.0 xhci-hcd xHCI Host Controller 0000:00:14.0, USB 2.00, 12 ports, nops]
  Port 6: 0000 off
$ sudo ./uhubctl -f -l 1 -p 6 -a 1
Current status for hub 1 [1d6b:0002 Linux 5.16.0 xhci-hcd xHCI Host Controller 0000:00:14.0, USB 2.00, 12 ports, nops]
  Port 6: 0000 off
Sent power on request
New status for hub 1 [1d6b:0002 Linux 5.16.0 xhci-hcd xHCI Host Controller 0000:00:14.0, USB 2.00, 12 ports, nops]
  Port 6: 0100 power

命令语法不太方便。下面简要解释。

uhubctl 基于 libusb,因此该工具也适用于其他操作系统。相比之下, hubpower 直接访问 /dev/bus/usb/ (或 /proc/bus/usb/)中 hub的 device file ,这仅适用于 Linux。

uhubctl 也支持 USB 3.x (参见 git commit 及其后续)。然而,似乎没有人关心当真正的 USB 设备连接到 hub时会发生什么: 我尝试重置 SuperSpeed 设备导致了奇怪的结果: 当返回 power 时,设备仍处于 Polling 状态,并且未被枚举。此外,当 power 关闭时,“lsusb -v”卡住了。所以那里发生了一些不好的事情。

这些是在 SuperSpeed port上关闭和重新打开电源的命令。下面是关于 SuperSpeed 的更多信息。

# ./uhubctl -f -e -l 2 -p 4 -a 0
# ./uhubctl -f -e -l 2 -p 4 -a 1

PORT_POWER 解释

当来自 host 的命令到达将 PORT_POWER 更改为零时, port 无条件地进入 Powered-off 状态。即使 hub 继续使用其 5V 电源为设备供电也是如此。 PORT_POWER 变为零还有其他原因,特别是 port 上的 overcurrent 条件(设备消耗过多电流)。

将 PORT_POWER 更改为 '1' 的唯一方法是通过来自 host的命令。这会将 port 置于 Disconnected 状态。没有任何连接的 USB ports 通常处于这种状态。当在 port上检测到设备时,状态将在短暂延迟后更改为 Disabled 。如果设备已连接,并且 PORT_POWER 更改为 '1',则会立即发生这种情况。

从这种状态开始,激活设备的唯一途径是重置 port (对于 PORT_RESET,见下文)。只有 host 可以做到这一点。因此, hub 唯一能做的就是通知 host 有连接的设备需要注意。

这是 port的 status bits 之一的用武之地: PORT_CONNECTION。当 port 处于 Powered-off 状态或 Disconnected 状态时,此 bit 必须为零。当 port 从 Disconnected 状态转换为 Disabled 状态时, PORT_CONNECTION 变为 '1' 。 PORT_CONNECTION 中的更改会生成 hub event,因此会通知 driver (即在启用 USB_PORT_FEAT_C_CONNECTION 的情况下对 kernel的 hub.c 中的 port_event() 进行函数调用)。 driver 通过重置 port (通过将 port的 PORT_RESET 位更改为 '1')和枚举连接的设备来响应。

这一切都与 USB 2.0有关。 USB 2.0 规范中的图 11-10 显示了 hub的 port 如何更改状态。

直接控制 PORT_RESET 和 PORT_ENABLE

hubpower 还可以直接更改另外两个属性: PORT_RESET 和 PORT_ENABLE。事实上,我将此功能添加到我自己的此工具的 fork 中。但是请注意,您所能做的就是故意使 USB 设备发生故障(从而使计算机重置设备以修复该问题)。现在更详细:

host 应将PORT_RESET 设置为 '1' ,以便根据 USB 2.0 规范中的第 11.5.1.5 节启动 port reset 。 hub 在完成重置后将 PORT_RESET 更改回 '0' 。 hub 永远不会主动启动 port reset ,并且不允许 host 将 '0' 写入此属性(第 11.24.2.7.1.5 节)。

如果 port 处于 Powered-off 或 Disconnected 状态,则此 hub 将忽略 PORT_RESET 。

关于 PORT_ENABLE: 当此属性更改为 '0'时, port 更改为 Disabled 状态。这可能是由于来自 host的请求以及 USB 设备断开连接、 port 处于断电状态或 reset 过程中的错误所致。

PORT_ENABLE 只能根据 host 的 port reset 请求更改为 '1' ( USB 2.0 规范中的第 11.24.2.7.1.2 节)。

因此不允许 host 将 PORT_RESET 更改为 '0' 或将 PORT_ENABLE 更改为 '1'。尝试这样做将导致来自 hub 的错误响应(相关的 ioctl() 命令将返回 error status)。

hubpower 可以通过将 port的 PORT_RESET 更改为 '1'来直接请求重置。这将重置 USB 设备,并且设备将因此忘记其 bus address 。因此该设备将无法再访问。

这个指令是直接发给 hub的,所以 Linux kernel 中的 hub的 driver 不会知道有这个发生。事实上,计算机在尝试访问 USB 设备之前不会注意到任何更改。接下来会发生什么取决于设备的 driver。该设备将被视为有一些硬件错误。因此,将采取某种纠错措施。这很可能包括重置。

所以直接用 hubpower 引起reset应该可以达到预期的效果,但是会有很多不必要的戏剧性。 PORT_POWER 更优雅地做到了这一点。直接 PORT_RESET 的唯一可能优势是 driver 可能会说“嘿,这个设备确实有问题,让我们采取一些激烈的措施来修复它”。这可能会有所帮助。

至于操纵 PORT_ENABLE,同样会发生: 设备会突然消失。即使在这种情况下,计算机也不会立即知道发生了什么: 根据 USB 2.0 specification中的 11.24.2.7.2.2 节,仅当 port 由于链接错误而被禁用时,才会触发 PORT_ENABLE (即 C_PORT_ENABLE)上的更改通知。该规范明确表示,此通知不是出于任何其他原因发出的。

因此,将 PORT_ENABLE 更改为零与直接更改 PORT_RESET 具有大致相同的效果。有一个缺点: 根据 USB 3.0 规范的第 10.14.2.6.1 节, PORT_ENABLE “is not supported by SuperSpeed hubs”。

SuperSpeed (USB 3.x)

首先也是最重要的: 如果您是因为 USB 3.x 设备出现问题而阅读本文,请问问自己是否真的需要 USB 3.x 提供的 data rate 。如果答案是否定的,请尝试通过不支持 USB 3.x 的 USB hub (或较短的 USB 2.0 电缆)将设备连接到计算机。仅此一项就可以解决问题。

SuperSpeed USB (与 USB 3.x含义相同)与 USB 2.0并存。每个 SuperSpeed 设备实际上由两个设备组成: 一个单独的设备用于 SuperSpeed,另一个单独的设备用于 USB 2.0。这两个 USB versions 中的每一个都依赖于 USB cable的单独电线。它们在电子上和概念上都是相互独立的。

USB 规范要求每个 SuperSpeed 设备都包含这两个设备,尽管实际上并不需要。换句话说,不支持 USB 2.0 的 SuperSpeed 设备在连接到 SuperSpeed port时可以正常工作。

当 SuperSpeed 设备连接到 SuperSpeed port时,首先尝试通过 SuperSpeed 接口进行连接。如果失败,将尝试通过 USB 2.0 进行连接。实际上(根据规范), USB 设备绝不会同时通过两个版本进行连接。但是,这是可能的,并且会使 USB 设备的行为就像是两个独立的设备一样。

一个 SuperSpeed hub 由两个并联的 hubs 组成: 一个用于 USB 2.0 ,一个用于 SuperSpeed。当您将外部 SuperSpeed USB hub 连接到计算机时,系统会添加两个 hubs 。它们显示为两个独立的设备。普通 USB 设备不允许同时使用两个版本,但 hub 必须这样做。

如果 SuperSpeed hub 连接到 USB 2.0 port,它的行为就像一个普通的 USB 2.0 hub。

一般来说,这两个 hubs 中的每一个都独立于另一个运行。每个 hub 都有自己的 ports,而这些 ports 中的每一个都独立运行。特别是,如果 port 的参数在其中一个并行 hubs上发生变化,则这对另一个 hub的 ports没有影响。

另一个结论是,如果“lsusb -t”显示一个设备通过 SuperSpeed root hub连接到计算机,则它作为 SuperSpeed 设备运行。换句话说,它的数据速率是 5 Gbit/s 或更高。同样,如果此设备通过 USB 2.0 root hub连接,则其数据速率为 480 Mbit/s 或更低。

SuperSpeed 和 PORT_POWER

回想一下, hubpower 实际上所做的是更改 port的 PORT_POWER 属性。

但是一个 SuperSpeed hub 是由两个并联的 hubs 组成的。这两个 hubs 中的每一个对于每个 port都有自己独立的 PORT_POWER 属性。那么 hub 应该什么时候关闭 VBUS power呢?每个物理 power switch 都依赖于两个 PORT_POWER 属性,每个并行 hubs都有一个属性。

USB 3.0 specification 的表10-2给出了 hub 是否应该开启电源的真值表。可以概括如下: 如果 hub 仅作为 USB 2.0 hub 运行(例如,连接到不支持 SuperSpeed的计算机),则它遵循 USB 2.0的 PORT_POWER。如果它作为 SuperSpeed hub 连接(或两个并联的 hubs 都连接),只有当两个 PORT_POWER 都为零时, VBUS 才会关闭。

如果这听起来很复杂,那实际上是简单的部分: hub 的 SuperSpeed 部分具有不同的内部 state machine。这是意料之中的,因为 link training 的做法不同。但是这个 state machine 具有三种不同的状态(而不是一种,如 USB 2.0),当 PORT_POWER 为零时,它们是符合条件的:

最后两个状态的目的是确保如果有自己的电源的 SuperSpeed 设备连接到 port,则连接不会回退到 USB 2.0。发生这种情况是因为设备无法识别它已连接到 SuperSpeed port。

那么我们从中学到了什么?主要是通过在 SuperSpeed hub 上更改 PORT_POWER 来重置设备并不像在 USB 2.0 hub上那么简单。

SuperSpeed: warm reset 和 hot reset

USB 2.0 有一种重置设备的简单方法: 两条线都通过 hub 连接到 ground (SE0) 10 毫秒。另一方面, SuperSpeed 设备有两种 reset 设备的方法: warm reset 和 hot reset。这些不应与 PowerOn Reset 和 Inband Reset混淆,它们是用于定义重置原因的术语。 Inband Reset 表示重置是由于 host的请求而发生的。这可能导致 warm reset 或 hot reset,具体取决于请求的类型(更多内容见下文)。

区分 warm reset 和 hot reset很重要: 特别是, warm reset 涉及停止 data stream 并从头开始启动它。 hot reset 在 data stream 本身上发送,并保持此 data stream 运行。因此 hot reset 的速度要快得多,但如果 data stream 出现问题可以通过重启来解决,则需要 warm reset 。这种问题的一个例子是 physical layer上是否有 bit errors 。取下 bitstream 并重新开始可能会解决此问题,可能是因为它可以纠正 equalizer的次优调整。

回想一下, usbreset 执行 ioctl() 和 USBDEVFS_RESET。在发生的所有其他事情中,这会将 PORT_RESET 更改为零,而不管设备的 USB 版本(从 Linux kernel v5.16开始)。

根据 USB 3.0 规范第 7.4.2 节, PORT_RESET 请求会产生 Hot Reset。这意味着如果 data stream 处于活动状态,则不会被拆除,而是在这个 data stream上发送复位命令。该规范还定义了 BH_PORT_RESET (feature 编号 28),它强制使用 warm reset (除非禁用 port )。此重置更为基本: 它关闭 data stream,并重新启动程序以再次启动它(通过 LFPS signaling)。重要的区别在于,如果 data stream 需要重启, BH_PORT_RESET 会执行,但 PORT_RESET 不会。

新 SuperSpeed 设备的连接涉及 Warm Reset。所以很遗憾,显然没有工具可以在 SuperSpeed port上使用 PORT_POWER 来解决问题。上文提到, uhubctl 在技术上可以做到这一点,但设备最终陷入了混乱状态。


剩余的笔迹

这些是可能有用的随机信息,但没有适当的上下文。

此页面由英文自动翻译。 如果有不清楚的地方,请参考原始页面
Copyright © 2021-2024. All rights reserved. (6f913017)