소개
완벽한 세상에서 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를 다운로드하고 compilation에 gcc를 사용하십시오.
$ 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
이 세션에서 설명하는 내용:
- arguments가 없으면 usbreset은 USB 장치 목록으로 응답합니다. lsusb에서도 동일한 정보를 얻습니다.
- 장치를 실제로 재설정하려면 root 여야 합니다(따라서 sudo).
- 장치는 bus address (bus number 및 device number)로 선택할 수 있습니다. bus address는 장치가 연결될 때마다 변경됩니다.
- 장치는 Vendor / Product IDs로 선택할 수도 있습니다. 이는 해당 종류의 USB 장치가 하나만 있을 때 선호되는 방법입니다.
- 장치가 USB bus 에서 주소를 변경하지 않았습니다(재설정 결과로 다시 열거되지 않음).
그렇다면 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에 있습니다. device number는 USB 장치가 열거될 때마다 변경됩니다.
그렇다면 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입니다( root hub로 기능하는 motherboard의 USB controller입니다).
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인 경우 이 address는 hub이 컴퓨터에 연결될 때마다 변경됩니다.
그러나 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사용)과 어떻게 다릅니까? 장치의 문제를 해결하기 위해 두 방법 모두 기본적으로 동일한 작업을 수행합니다. 재설정 명령을 보냅니다. 이것이 일어나는 방식은 극적으로 다르지만 여전히 문제를 해결할 가능성이 있는 재설정 명령입니다.
그러나 몇 가지 중요한 차이점이 있습니다.
- hubpower는 bus에서 장치가 인식되지 않아도 작동합니다. 예를 들어 컴퓨터가 장치를 여러 번 열거한 다음 포기한 경우입니다. 이 경우 장치는 물리적으로 컴퓨터에 연결될 수 있지만 장치에 bus address가 없기 때문에 usbreset은 쓸모가 없습니다.
- USB port가 비활성화될 때 hubpower 만이 도움이 될 수 있습니다. 때때로 컴퓨터는 이 port에서 여러 오류가 발생한 후 USB port를 완전히 무시합니다. hubpower가 이 문제를 해결해야 합니다.
- hubpower는 SuperSpeed (USB 3.x)에서 작동하지 않습니다. 아마도 지원을 추가하는 문제 일 것입니다. 아래에서 SuperSpeed 에 대해 자세히 알아보십시오.
- hubpower는 또한 USB 장치의 power supply을 제어할 수 있습니다(그러나 일반적으로 이런 일은 발생하지 않습니다). 이는 장치가 문제를 해결하기 위해 전력 재활용이 필요한 경우 이점이 됩니다.
- hubpower는 작업하기가 더 어렵습니다. hub의 ports 중 USB 장치에 연결된 ports를 찾아야 합니다. 그리고 hub의 bus address도 있습니다.
전기 장비 제어(?)
이 페이지의 주요 주제는 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에 따르면 hub 에는 port가 Powered-Off 상태에 있을 때 5V power supply을 port 로 끄는 power switches가 있을 수 있습니다. 또는 power switch를 사용하여 여러 ports ("ganged power switching")의 전원 공급 장치를 제어할 수 있습니다. 전원 공급 장치를 제어하는 목적은 주로 너무 많은 전류를 소모하는 USB 장치를 차단하여 나머지 ports가 계속 정상적으로 작동할 수 있도록 하는 것입니다.
그러나 이미 언급했듯이 물리적 전원 제어는 선택 사항입니다. hubpower가 실제로 하는 일은 port의 PORT_POWER 속성( USB specifications에서는 "feature"라고 함)의 값을 변경하는 것입니다. 이 변경 사항은 hub의 port의 두 가지 다른 측면과 관련이 있습니다.
- 필수적인: port의 논리적 상태. PORT_POWER가 0이면 port는 Powered-Off 상태(또는 Not Configured)에만 있을 수 있습니다. 즉, hub은 port에 전압이 없는 것처럼 작동해야 하므로 연결된 장치가 있는 경우 이를 무시합니다.
- 선택 과목: port의 전원 공급선에 VBUS ( 5V 전압)가 존재합니다. hub이 이 기능을 지원하지 않는 경우 PORT_POWER가 0인 경우에도 전압이 존재할 수 있습니다.
PORT_POWER는 아래에서 자세히 설명합니다.
내 hub이 전압을 제어합니까?
hub이 실제로 전압을 끄는지 어떻게 알 수 있습니까? 확실하게 알 수 있는 유일한 방법은 테스트하는 것입니다. USB 장치 가 아니지만 USB port에서 전력을 소비하는 모든 장치를 연결합니다. 실제 USB 장치는 혼란을 더할 수 있습니다. 예를 들어 광 마우스는 5V 전압이 남아 있더라도 일반적으로 전원 끄기 명령에 대한 응답으로 LED를 끕니다.
각 hub은 "lsusb -v"(사양의 섹션 11.23.2.1에 정의된 Hub Descriptor에서)로 표시되는 정보에서 전압 제어 여부와 세분성을 선언합니다. 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은 전압 제어를 지원하지 않는다는 점을 인정합니다.
전원 전환에 대한 정보 외에 "Hub Port Status"로 각 port 에 대한 상태 정보도 있습니다. 이러한 status bits는 USB 2.0 사양(섹션 11.24.2.7.1)의 표 11-21에 정의되어 있습니다. 이것은 hubpower에서 가져온 것과 동일한 정보입니다.
uhubctl 도구
USB hub 로 relay를 제어한다는 아이디어는 많은 이니셔티브의 동기가 되었습니다. 주로 이 프로젝트가 전압을 제어하는 USB hubs 목록을 유지하기 때문에 uhubctl을 살펴볼 가치가 있습니다.
이 도구는 분명히 전압 제어만을 위한 것이며 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
- -f는 hub이 각 개별 port에 대한 전압 제어를 지원하지 않는다고 보고하더라도 hub 와 함께 작동한다는 의미입니다.
- -e는 "정확한 위치"를 의미합니다. 즉, SuperSpeed port를 두 개의 hubs로 계산합니다.
- -l 2는 두 번째 hub을 의미합니다(첫 번째 hub은 내 컴퓨터의 USB 2.0 hub 였습니다).
- -p 4는 port 의 숫자 4를 의미합니다.
- -a 0은 전원을 끄는 것을 의미합니다(action #0).
- -a 1은 전원을 켜는 것을 의미합니다(action #1).
PORT_POWER 설명
host 에서 PORT_POWER를 0으로 변경하라는 명령이 도착하면 port는 무조건 Powered-off 상태로 들어갑니다. 이는 hub이 5V 전원 공급 장치를 장치에 계속 공급하는 경우에도 마찬가지입니다. PORT_POWER가 0이 되는 다른 이유, 특히 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. 이 bit은 port가 Powered-off 상태 또는 Disconnected 상태에 있을 때 0이어야 합니다. port가 Disconnected 상태에서 Disabled 상태로 전환될 때 PORT_CONNECTION은 '1' 로 변경됩니다. PORT_CONNECTION 의 변경 사항은 hub event를 생성하므로 driver 에 알립니다(즉, kernel의 hub.c 에서 port_event() 에 대한 함수 호출은 USB_PORT_FEAT_C_CONNECTION이 활성화된 상태에서 이루어짐). 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 장치를 고장나게 하는 것뿐입니다(따라서 컴퓨터가 장치를 재설정하여 문제를 해결하도록 함). 이제 더 자세히:
USB 2.0 사양의 섹션 11.5.1.5에 따라 port reset을 시작하려면 host 에서PORT_RESET을 '1' 로 설정해야 합니다. hub은 재설정을 완료한 후 PORT_RESET을 다시 '0' 로 변경합니다. hub은 자체 이니셔티브에서 port reset을 시작하지 않으며 host는 이 특성에 '0'을 쓸 수 없습니다(섹션 11.24.2.7.1.5).
이 hub은 port가 Powered-off 또는 Disconnected 상태인 경우 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를 사용하여 직접 재설정하면 원하는 결과를 얻을 수 있지만 불필요한 드라마가 많이 있습니다. PORT_POWER는 이 작업을 보다 우아하게 수행합니다. 직접 PORT_RESET 의 유일한 장점은 driver가 "이 장치에 정말 문제가 있습니다. 문제를 해결하기 위해 과감한 조치를 취합시다"라고 말할 수 있다는 것입니다. 그리고 그것은 도움이 될 수 있습니다.
PORT_ENABLE을 조작하는 경우에도 마찬가지입니다. 장치가 갑자기 사라집니다. 이 경우에도 컴퓨터는 어떤 일이 발생했는지 즉시 알지 못합니다. USB 2.0 specification의 섹션 11.24.2.7.2.2에 따르면 PORT_ENABLE (예: C_PORT_ENABLE)에 대한 변경 알림은 링크 오류로 인해 port가 비활성화된 경우에만 트리거됩니다. 사양에는 이 알림이 다른 이유로 생성되지 않는다고 명시적으로 나와 있습니다.
따라서 PORT_ENABLE을 0으로 변경하면 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는 독립적으로 작동합니다. 특히, 이러한 병렬 hubs중 하나에서 port 의 매개변수가 변경되면 다른 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는 각각의 병렬 hubs에서 하나씩 두 개의 PORT_POWER 속성에 의존합니다.
USB 3.0 specification 의 표 10-2는 hub이 전원 공급 장치를 활성화해야 하는지 여부에 대한 진리표를 제공합니다. 다음과 같이 요약할 수 있습니다. hub이 USB 2.0 hub 로만 작동하는 경우(예: SuperSpeed를 지원하지 않는 컴퓨터에 연결된 경우) USB 2.0의 PORT_POWER를 따릅니다. SuperSpeed hub 로 연결된 경우(또는 두 병렬 hubs가 연결된 경우) VBUS는 두 PORT_POWER가 모두 0인 경우에만 꺼집니다.
복잡하게 들린다면 실제로는 쉬운 부분이었습니다. hub 의 SuperSpeed 부분은 내부 state machine이 다릅니다. link training은 다르게 수행되기 때문에 상당히 예상됩니다. 그러나 이 state machine 에는 PORT_POWER가 0일 때 적합한 세 가지 상태( USB 2.0와 같은 하나 대신)가 있습니다.
- DSPORT.Powered-off는 port가 완전히 비활성 상태임을 의미합니다.
- DSPORT.Powered-off-detect, 이는 port가 SuperSpeed 링크 파트너를 감지하려고 시도함을 의미합니다.
- DSPORT.Powered-off-reset은 port가 warm reset을 link partner 로 수행함을 의미합니다( warm reset 에 대한 자세한 내용은 아래 참조).
마지막 두 상태의 목적은 자체 전원 공급 장치가 있는 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)로 10ms 동안 연결됩니다. 반면에 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은 USBDEVFS_RESET와 함께 ioctl()을 수행합니다. 발생하는 다른 모든 일 중에서 장치의 USB 버전( Linux kernel v5.16기준)에 관계없이 PORT_RESET이 0으로 변경됩니다.
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은 기술적으로 이를 수행할 수 있지만 장치는 지저분한 상태로 끝납니다.
남은 점
유용할 수 있지만 적절한 컨텍스트가 없는 임의의 정보입니다.
- PORT_POWER 와 같은 명령어의 코드는 USB 2.0 규격의 표 11-17과 USB 3.0 규격의 표 10-8에 Hub class feature selectors 로 나열되어 있다.
- PORT_RESET을 가능하게 하는 kernel 의 기능은 hub_port_reset()입니다. 그러나 실제로 port를 다시 초기화하기 위해 usb_reset_device()가 있는데, 이 driver 도 재설정을 위해 준비한 다음 usb_reset_and_verify_device()에 대한 함수 호출을 수행합니다. 이러한 기능은 모두 drivers/usb/core/hub.c에 정의되어 있으며 usb_reset_device() 만 내보냅니다.
- drivers/usb/core/devio.c에서 usb_reset_device()는 proc_resetdevice()에 의해 호출되며 관련 device file의 USBDEVFS_RESET ioctl() 에 의해 트리거될 수 있습니다. 이것이 usbreset이 하는 일입니다(위 참조).
- 이것은 linux_usbfs.c 의 libusb의 op_reset_device() 와 동일합니다(대신 IOCTL_USBFS_RESET을 사용하지만 USBDEVFS_RESET와 동일하며 둘 다 20이며 kernel의 include/uapi/linux/usbdevice_fs.h와 비교). libusb의 기능도 인터페이스를 해제합니다.proc_resetdevice()는 device의 인터페이스가 요청된 경우 이를 정중하게 거부합니다.
- hub.c에서 port_event()는 hub_event()에 의해 호출됩니다. 전자는 port비트의 변화를 감지하는 것입니다. hub_event()는 work item로, kick_hub_wq() 에 의해 시작됩니다(특히 hub_irq()에 의해, 이 목적을 위해 지정된 hub의 IN endpoint에 도착하는 상태 변경 알림에 대한 응답으로 "fires on port status changes and various faults").