mirror of
https://github.com/mvp/uhubctl.git
synced 2026-05-17 08:26:29 +03:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
352f5878e9 | ||
|
|
169842ae97 | ||
|
|
8de8c9487f | ||
|
|
3dbc1d9e41 | ||
|
|
83ce372810 | ||
|
|
f22541cf64 | ||
|
|
2df4681826 | ||
|
|
359d887927 | ||
|
|
1f920f6b15 | ||
|
|
746891d888 | ||
|
|
83f624f3b5 | ||
|
|
61fd83ff10 | ||
|
|
cd99f0de34 | ||
|
|
3d804c1ab7 | ||
|
|
3e86729800 | ||
|
|
d556081fbb | ||
|
|
1199b9ddbc | ||
|
|
f70c2ced96 | ||
|
|
4deae1731c | ||
|
|
5cc9f154e1 | ||
|
|
7a0fbd266f | ||
|
|
e18434cd2e | ||
|
|
a34319a6d4 | ||
|
|
d18db0d2be | ||
|
|
f37dcb5cbf | ||
|
|
5bb7197f51 | ||
|
|
5b2c40db83 | ||
|
|
0d28753bcf | ||
|
|
54ab9e72d4 | ||
|
|
b16ba1b36d | ||
|
|
30372ce59f | ||
|
|
a9f2e7832d | ||
|
|
cec0435144 | ||
|
|
586b424557 | ||
|
|
1d3b841429 | ||
|
|
2f45ac6138 | ||
|
|
4c235868eb | ||
|
|
33f1ecb2dd | ||
|
|
8f355837b7 | ||
|
|
f2d97a3aad | ||
|
|
e847dc461d | ||
|
|
61fd84b0ad | ||
|
|
a54835e0ea | ||
|
|
41e1bacf41 | ||
|
|
2be4125977 | ||
|
|
2ef5f0eb0b | ||
|
|
19dfdad7f6 | ||
|
|
ce2fd9a419 |
@@ -2,8 +2,8 @@ class Uhubctl < Formula
|
||||
desc "USB hub per-port power control"
|
||||
homepage "https://github.com/mvp/uhubctl"
|
||||
head "https://github.com/mvp/uhubctl.git"
|
||||
url "https://github.com/mvp/uhubctl/archive/v2.4.0.tar.gz"
|
||||
sha256 "391f24fd1f89cacce801df38ecc289b34c3627bc08ee69eec515af7e1a283d97"
|
||||
url "https://github.com/mvp/uhubctl/archive/v2.5.0.tar.gz"
|
||||
sha256 "d4452252f7862f7a45dd9c62f2ea7cd3a57ab5f5ab0e54a857d4c695699bbba3"
|
||||
license "GPL-2.0"
|
||||
|
||||
depends_on "libusb"
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
uhubctl – USB hub per-port power control.
|
||||
|
||||
Copyright (c) 2009-2022, Vadim Mikhailov
|
||||
Copyright (c) 2009-2024, Vadim Mikhailov
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
158
README.md
158
README.md
@@ -18,44 +18,47 @@ This is list of known compatible USB hubs:
|
||||
|
||||
| Manufacturer | Product | Ports | USB | VID:PID | Release | EOL |
|
||||
|:-------------------|:-----------------------------------------------------|:------|:----|:----------|:--------|:-----|
|
||||
| Acer | BE270U monitor ([see](https://tinyurl.com/acer550)) | 4 | 3.0 |`2109:2811`| 2016 | |
|
||||
| AmazonBasics | HU3641V1 ([RPi issue](https://goo.gl/CLt46M)) | 4 | 3.0 |`2109:2811`| 2013 | |
|
||||
| AmazonBasics | HU3770V1 ([RPi issue](https://goo.gl/CLt46M)) | 7 | 3.0 |`2109:2811`| 2013 | |
|
||||
| AmazonBasics | HU9003V1EBL, HUC9003V1EBL | 7 | 3.1 |`2109:2817`| 2018 | |
|
||||
| AmazonBasics | HU9002V1SBL, HU9002V1EBL, HU9002V1ESL ([note](https://bit.ly/3awM2Ei)) | 10 | 3.1 |`2109:2817`| 2018 | |
|
||||
| AmazonBasics | HUC9002V1SBL, HUC9002V1EBL, HUC9002V1ESL | 10 | 3.1 |`2109:2817`| 2018 | |
|
||||
| AmazonBasics | U3-7HUB (only works for 1 charge port) | 7 | 3.0 |`2109:2813`| 2020 | |
|
||||
| Anker | AK-A83650A1 ([note](https://git.io/JzpPb)) | 4 | 3.1 |`2109:0817`| 2020 | |
|
||||
| Anker | AK-68ANHUB-BV7A-0004 ([note](https://git.io/JLnZb)) | 7 | 3.0 |`2109:0812`| 2014 | |
|
||||
| Apple | Pro Display XDR MWPE2LL/A (internal USB hub) | 4 | 2.0 |`05AC:9139`| 2019 | |
|
||||
| Apple | Thunderbolt Display 27" (internal USB hub) | 6 | 2.0 | | 2011 | 2016 |
|
||||
| Apple | USB Keyboard With Numeric Pad (internal USB hub) | 3 | 2.0 | | 2011 | |
|
||||
| Asus | Z77 Sabertooth Motherboard (onboard USB hub) | 6 | 2.0 | | 2012 | |
|
||||
| Asus | Z87-PLUS Motherboard (onboard USB hub) | 4 | 3.0 | | 2013 | 2016 |
|
||||
| Aukey | CB-C59 | 4 | 3.1 |`2109:2813`| 2017 | |
|
||||
| Aukey | CB-C59 | 4 | 3.0 |`2109:2813`| 2017 | |
|
||||
| B+B SmartWorx | UHR204 | 4 | 2.0 |`0856:DB00`| 2013 | |
|
||||
| B+B SmartWorx | USH304 | 4 | 3.0 |`04B4:6506`| 2017 | |
|
||||
| B+B SmartWorx | USH304 | 4 | 3.0 |`04B4:6506`| 2017 | 2019 |
|
||||
| Basler | 2000036234 | 4 | 3.0 |`0451:8046`| 2016 | |
|
||||
| Belkin | F5U101 | 4 | 2.0 |`0451:2046`| 2005 | 2010 |
|
||||
| BenQ | PD2700U 4K Monitor (works only in USB2 mode) | 4 | 3.1 |`05E3:0610`| 2018 | |
|
||||
| Belkin | F5U238UKCRL-MOB | 4 | 2.0 |`0409:0059`| 2004 | 2010 |
|
||||
| BenQ | PD2700U 4K Monitor (works only in USB2 mode) | 4 | 3.0 |`05E3:0610`| 2018 | |
|
||||
| BenQ | PD3220U | 4 | 3.1 |`05E3:0610`| 2019 | |
|
||||
| Buffalo | BSH4A05U3BK | 4 | 3.0 |`05E3:0610`| 2015 | |
|
||||
| Bytecc | BT-UH340 ([warning](https://bit.ly/35BNi5U)) | 4 | 3.0 |`2109:8110`| 2010 | |
|
||||
| Centech | CT-USB4HUB ReTRY HUB | 4 | 3.1 |`0424:2744`| 2017 | |
|
||||
| Centech | CT-USB4HUB ReTRY HUB | 4 | 3.0 |`0424:2744`| 2017 | |
|
||||
| Circuitco | Beagleboard-xM (internal USB hub) | 4 | 2.0 |`0424:9514`| 2010 | |
|
||||
| Club3D | CSV-3242HD Dual Display Docking Station | 4 | 3.0 |`2109:2811`| 2015 | |
|
||||
| CyberPower | CP-H420P | 4 | 2.0 |`0409:0059`| 2004 | |
|
||||
| Coolgear | USBG-12U2ML | 12 | 2.0 |`05e3:0607`| 2015 | |
|
||||
| Cypress | CY4608 HX2VL devkit ([note](https://bit.ly/3sMPfpu)) | 4 | 2.0 |`04B4:6570`| 2012 | |
|
||||
| D-Link | DUB-H4 rev D,E (black). Note: rev A,C,F not supported| 4 | 2.0 |`05E3:0608`| 2012 | |
|
||||
| D-Link | DUB-H7 rev A (silver) | 7 | 2.0 |`2001:F103`| 2005 | 2010 |
|
||||
| D-Link | DUB-H7 rev D,E (black). Rev B,C,F,G not supported | 7 | 2.0 |`05E3:0608`| 2012 | |
|
||||
| Dell | P2416D 24" QHD Monitor ([note](https://git.io/JUAu8))| 4 | 2.0 | | 2017 | |
|
||||
| Dell | S2719DGF 27" WQHD Gaming-Monitor | 5 | 3.1 |`0424:5734`| 2018 | |
|
||||
| Dell | S2719DGF 27" WQHD Gaming-Monitor | 5 | 3.0 |`0424:5734`| 2018 | |
|
||||
| Dell | UltraSharp 1704FPT 17" LCD Monitor | 4 | 2.0 |`0424:A700`| 2005 | 2015 |
|
||||
| Dell | UltraSharp U2415 24" LCD Monitor | 5 | 3.0 | | 2014 | |
|
||||
| Dell | UltraSharp U3419W 34" Curved Monitor | 6 | 3.0 | | 2020 | |
|
||||
| Delock | 62537 | 4 | 3.1 | | 2020 | |
|
||||
| Dell | Wyse 3040 ([-f required](https://tinyurl.com/wyse3k))| 6 | 3.0 | | 2017 | |
|
||||
| Delock | 62537 | 4 | 3.0 | | 2017 | 2021 |
|
||||
| Delock | 87445 ([note](https://git.io/Jsuz5)) | 4 | 2.0 |`05E3:0608`| 2009 | 2013 |
|
||||
| Elecom | U2H-G4S | 4 | 2.0 | | 2006 | 2011 |
|
||||
| ExSys | EX-1113HMS | 16 | 3.1 | | 2018 | |
|
||||
| Gigabyte | G27Q monitor ([see](http://tinyurl.com/G27Q551) | 4 | 3.0 |`2109:0817`| 2020 | |
|
||||
| GlobalScale | ESPRESSObin SBUD102 V5 | 1 | 3.0 |`1D6B:0003`| 2017 | |
|
||||
| Hardkernel | ODROID-C4 ([note](https://git.io/JG0mP)) | 4 | 3.0 | | 2020 | |
|
||||
| Hawking Technology | UH214 | 4 | 2.0 | | 2003 | 2008 |
|
||||
@@ -66,8 +69,13 @@ This is list of known compatible USB hubs:
|
||||
| j5create | JUH377 ([note](https://bit.ly/3Mx9eQI)) | 7 | 3.0 | | 2016 | |
|
||||
| j5create | JUH470 ([note](https://bit.ly/3CRWamP)) | 3 | 3.0 |`05E3:0610`| 2014 | |
|
||||
| Juiced Systems | 6HUB-01 | 7 | 3.0 |`0BDA:0411`| 2014 | 2018 |
|
||||
| LG Electronics | 27MD5KL-B monitor | 4 | 3.1 |`043E:9A60`| 2019 | |
|
||||
| KUNBUS GmbH | RevPi Connect (+) / S / SE | 2 | 2.0 |`0424:9514`| 2018 | |
|
||||
| KUNBUS GmbH | RevPi Connect 4 | 2 | 3.0 | | 2022 | |
|
||||
| KUNBUS GmbH | RevPi Core 3 / S / SE | 2 | 2.0 |`0424:9514`| 2017 | |
|
||||
| LG Electronics | 27MD5KL-B monitor | 4 | 3.0 |`043E:9A60`| 2019 | |
|
||||
| LG Electronics | 27GL850-B monitor | 4 | 3.0 |`0451:8142`| 2019 | |
|
||||
| LG Electronics | 27UK850-W monitor | 2 | 3.0 | | 2018 | |
|
||||
| LG Electronics | 27UN83A-W monitor | 2 | 3.0 |`0451:8142`| 2020 | |
|
||||
| LG Electronics | 38WK95C-W monitor | 4 | 3.0 |`0451:8142`| 2018 | |
|
||||
| Lenovo | ThinkPad Ultra Docking Station (40A20090EU) | 6 | 2.0 |`17EF:100F`| 2015 | |
|
||||
| Lenovo | ThinkPad Ultra Docking Station (40AJ0135EU) | 7 | 3.1 |`17EF:3070`| 2018 | |
|
||||
@@ -75,38 +83,49 @@ This is list of known compatible USB hubs:
|
||||
| Lenovo | ThinkPad X6 Ultrabase 42W3107 | 4 | 2.0 |`17EF:1000`| 2006 | 2009 |
|
||||
| Lenovo | ThinkPlus 4-in-1 USB-C hub 4X90W86497 | 3 | 3.0 | | 2021 | |
|
||||
| Lenovo | ThinkVision T24i-10 Monitor | 4 | 2.0 |`17EF:0610`| 2018 | |
|
||||
| Lenovo | USB-C to 4 Port USB-A Hub | 4 | 2.0 |`17EF:103A`| 2020 | |
|
||||
| Lindy | USB serial converter 4 port | 4 | 1.1 |`058F:9254`| 2008 | |
|
||||
| Linksys | USB2HUB4 ([note](https://git.io/JYiDZ)) | 4 | 2.0 | | 2004 | 2010 |
|
||||
| Maplin | A08CQ | 7 | 2.0 |`0409:0059`| 2008 | 2011 |
|
||||
| Metadot | Das Keyboard 4 | 2 | 3.0 | | 2014 | |
|
||||
| Microchip | EVB9512 | 2 | 2.0 | | 2009 | |
|
||||
| Microchip | EVB-USB2517 | 7 | 2.0 | | 2008 | |
|
||||
| Microchip | EVB-USB2534BC | 4 | 2.0 | | 2013 | |
|
||||
| Microchip | EVB-USB5807 | 7 | 3.1 | | 2016 | |
|
||||
| Microchip | EVB-USB5807 | 7 | 3.0 | | 2016 | |
|
||||
| Moxa | Uport-407 | 7 | 2.0 |`110A:0407`| 2009 | |
|
||||
| NVidia | Jetson Nano B01 ([details](https://git.io/JJaFR)) | 4 | 3.0 | | 2019 | |
|
||||
| NVidia | Jetson Xavier NX ([details](https://bit.ly/3PN2DDp)) | 4 | 3.0 | | 2020 | |
|
||||
| Phidgets | HUB0003_0 | 7 | 2.0 |`1A40:0201`| 2017 | |
|
||||
| Philips | 346B1C UltraWide 34" Curved Monitor | 4 | 3.0 |`05E3:0610`| 2019 | |
|
||||
| Plugable | USB3-HUB7BC | 7 | 3.0 |`2109:0813`| 2015 | |
|
||||
| Plugable | USB3-HUB7C (only works for 2 charge ports) | 7 | 3.0 |`2109:0813`| 2015 | |
|
||||
| Plugable | USBC-HUB7BC (works for 6/7 ports, not the rightmost) | 7 | 3.0 |`2109:0817`| 2021 | |
|
||||
| Plugable | USB3-HUB7-81X (only works for 2 charge ports) | 7 | 3.0 |`2109:0813`| 2012 | |
|
||||
| Plugable | USB3-HUB10-C2 (only works for 2 charge ports) | 10 | 3.0 | | 2014 | |
|
||||
| Port Inc | NWUSB01 | 4 | 1.1 |`0451:1446`| 1999 | 2003 |
|
||||
| Raspberry Pi | B+, 2B, 3B ([see below](#raspberry-pi-b2b3b)) | 4 | 2.0 | | 2011 | |
|
||||
| Raspberry Pi | 3B+ ([see below](#raspberry-pi-3b)) | 4 | 2.0 |`0424:2514`| 2018 | |
|
||||
| Raspberry Pi | 4B ([see below](#raspberry-pi-4b)) | 4 | 3.0 |`2109:3431`| 2019 | |
|
||||
| Raspberry Pi | 5 ([see below](#raspberry-pi-5)) | 4 | 3.0 |`1d6b:0002`| 2023 | |
|
||||
| Renesas | uPD720202 PCIe USB 3.0 host controller | 2 | 3.0 | | 2013 | |
|
||||
| Rosewill | RHUB-210 | 4 | 2.0 |`0409:005A`| 2011 | 2014 |
|
||||
| Rosonway | RSH-518C ([note](https://bit.ly/3kYZUsA)) | 7 | 3.0 |`2109:0817`| 2021 | |
|
||||
| Rosonway | RSH-A10 ([see](https://tinyurl.com/2ppyyaj8)) | 10 | 3.0 |`0bda:0411`| 2020 | |
|
||||
| Rosonway | RSH-A13 ([warning](https://bit.ly/3OToUOL)) | 13 | 3.1 |`2109:2822`| 2021 | |
|
||||
| Rosonway | RSH-A16 ([note](https://git.io/JTawg), [warning](https://bit.ly/39B0tGS)) | 16 | 3.0 |`0bda:0411`| 2020 | |
|
||||
| Rosonway | RSH-A104 ([USB2 only](https://bit.ly/3A0qiKF)) | 4 | 3.1 |`2109:2822`| 2022 | |
|
||||
| Rosonway | RSH-A107 (aka ikuai A107-5) | 7 | 3.1 |`0bda:5411`| 2022 | |
|
||||
| Rosonway | RSH-ST07C ([only 4](https://tinyurl.com/4pjnujrn)) | 7 | 3.0 |`2109:2822`| 2023 | |
|
||||
| Sanwa Supply | USB-HUB14GPH | 4 | 1.1 | | 2001 | 2003 |
|
||||
| Seagate | Backup Plus Hub STEL8000100 | 2 | 3.0 |`0BC2:AB44`| 2016 | |
|
||||
| Seeed Studio | reTerminal CM4104032 | 2 | 2.0 |`0424:2514`| 2021 | |
|
||||
| StarTech | HB30A4AIB ([warning](https://tinyurl.com/ycxravwk)) | 4 | 3.0 |`2109:2817`| 2018 | |
|
||||
| Sunix | SHB4200MA | 4 | 2.0 |`0409:0058`| 2006 | 2009 |
|
||||
| System Talks | Sugoi USB2-HUB4X | 4 | 2.0 | | 2007 | |
|
||||
| Targus | PA095UZ | 2 | 2.0 | | 2004 | |
|
||||
| Targus | PAUH212/PAUH212U | 7 | 2.0 | | 2004 | 2009 |
|
||||
| Texas Instruments | TUSB4041PAPEVM | 4 | 2.1 |`0451:8142`| 2015 | |
|
||||
| UUGear | MEGA4 (for Raspberry Pi 4B) | 4 | 3.1 |`2109:0817`| 2021 | |
|
||||
| UUGear | MEGA4 (for Raspberry Pi 4B) | 4 | 3.0 |`2109:0817`| 2021 | |
|
||||
| VirtualHere | USB3 4-port hub ([note](https://tinyurl.com/vhusb)) | 4 | 3.0 | | 2024 | |
|
||||
|
||||
This table is by no means complete.
|
||||
If your hub works with `uhubctl`, but is not listed above, please report it
|
||||
@@ -138,9 +157,6 @@ Compiling
|
||||
This utility was tested to compile and work on Linux
|
||||
(Ubuntu/Debian, Redhat/Fedora/CentOS, Arch Linux, Gentoo, openSUSE, Buildroot), FreeBSD, NetBSD, SunOS and MacOS.
|
||||
|
||||
> :warning: MacOS 12.4 x86 has [USB stack bug](https://github.com/libusb/libusb/issues/1156) which breaks `uhubctl` operation.
|
||||
Solution is to upgrade to MacOS 12.5 which has this bug fixed.
|
||||
|
||||
While `uhubctl` compiles on Windows, USB power switching does not work on Windows because `libusb`
|
||||
is using `winusb.sys` driver, which according to Microsoft does not support
|
||||
[necessary USB control requests](https://social.msdn.microsoft.com/Forums/sqlserver/en-US/f680b63f-ca4f-4e52-baa9-9e64f8eee101).
|
||||
@@ -225,23 +241,23 @@ To fix USB permissions, first run `sudo uhubctl` and note all `vid:pid` for hubs
|
||||
Then, add udev rules like below to file `/etc/udev/rules.d/52-usb.rules`
|
||||
(replace `2001` with your hub vendor id, or completely remove `ATTR{idVendor}` filter to allow any USB hub access):
|
||||
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0666", ATTR{idVendor}=="2001"
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", MODE="0666", ATTR{idVendor}=="2001"
|
||||
# Linux 6.0 or later (its ok to have this block present for older Linux kernels):
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", \
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", \
|
||||
RUN="/bin/sh -c \"chmod -f 666 $sys$devpath/*-port*/disable || true\""
|
||||
|
||||
Note that for USB3 hubs, some hubs use different vendor ID for USB2 vs USB3 components of the same chip,
|
||||
and both need permissions to make uhubctl work properly.
|
||||
E.g. for Raspberry Pi 4B, you need to add these 2 lines (or remove idVendor filter):
|
||||
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0666", ATTR{idVendor}=="2109"
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0666", ATTR{idVendor}=="1d6b"
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", MODE="0666", ATTR{idVendor}=="2109"
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", MODE="0666", ATTR{idVendor}=="1d6b"
|
||||
|
||||
If you don't like wide open mode `0666`, you can restrict access by group like this:
|
||||
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0664", GROUP="dialout"
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", MODE="0664", GROUP="dialout"
|
||||
# Linux 6.0 or later (its ok to have this block present for older Linux kernels):
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", \
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", \
|
||||
RUN+="/bin/sh -c \"chown -f root:dialout $sys$devpath/*-port*/disable || true\"" \
|
||||
RUN+="/bin/sh -c \"chmod -f 660 $sys$devpath/*-port*/disable || true\""
|
||||
|
||||
@@ -309,16 +325,13 @@ Per-port power switching:
|
||||
|
||||
#### _USB devices are not removed after port power down on Linux_
|
||||
|
||||
> :arrow_right: This is fixed by [#450](https://github.com/mvp/uhubctl/pull/450) if you are using Linux kernel 6.0 or later.
|
||||
|
||||
After powering down USB port, udev does not get any event, so it keeps the device files around.
|
||||
However, trying to access the device files will lead to an IO error.
|
||||
|
||||
This is Linux kernel issue. It may be eventually fixed in kernel, see more discussion [here](https://bit.ly/2JzczjZ).
|
||||
Basically what happens here is that kernel USB driver knows about power off,
|
||||
but doesn't send notification about it to udev.
|
||||
This is Linux kernel [issue](https://bit.ly/2JzczjZ) and is [fixed](https://github.com/mvp/uhubctl/pull/450)
|
||||
since uhubctl 2.5.0 for systems with Linux kernel 6.0 or later.
|
||||
|
||||
You can use this workaround for this issue:
|
||||
If you are still using Linux 5.x or older, you can use this workaround for this issue:
|
||||
|
||||
sudo uhubctl -a off -l ${location} -p ${port}
|
||||
sudo udevadm trigger --action=remove /sys/bus/usb/devices/${location}.${port}/
|
||||
@@ -329,13 +342,15 @@ When you turn power back on, device should re-enumerate properly (no need to cal
|
||||
|
||||
#### _Power comes back on after few seconds on Linux_
|
||||
|
||||
> :arrow_right: This is fixed by [#450](https://github.com/mvp/uhubctl/pull/450) if you are using Linux kernel 6.0 or later.
|
||||
|
||||
Some device drivers in kernel are surprised by USB device being turned off and automatically try to power it back on.
|
||||
|
||||
You can use option `-r N` where N is some number from 10 to 1000 to fix this -
|
||||
This is Linux kernel [issue](https://bit.ly/2JzczjZ) and is [fixed](https://github.com/mvp/uhubctl/pull/450)
|
||||
since uhubctl 2.5.0 for systems with Linux kernel 6.0 or later.
|
||||
|
||||
If you are still using Linux 5.x or older:
|
||||
|
||||
You can use option `-r N`, where N is some number from 10 to 1000 to fix this -
|
||||
`uhubctl` will try to turn power off many times in quick succession, and it should suppress that.
|
||||
This may be eventually fixed in kernel, see more discussion [here](https://bit.ly/2JzczjZ).
|
||||
|
||||
Disabling USB authorization for device in question before turning power off with `uhubctl` should help:
|
||||
|
||||
@@ -405,39 +420,70 @@ to make power switching work on RPi 4B.
|
||||
|
||||
* USB2 hub `3`, 1 port, OTG controller. Power switching is [not supported](https://git.io/JUc5Q).
|
||||
|
||||
##### Raspberry Pi 5
|
||||
|
||||
Raspberry Pi 5 has two USB2 ports and two USB3 ports (total 4).
|
||||
These ports are connected to 4 distinct USB hubs `1`,`2`,`3`,`4` in really weird configuration.
|
||||
If USB3 device is connected to blue socket, it will be detected on USB3 hub `2` or `4`.
|
||||
If USB2 device is connected to any socket or USB3 device connected to black socket,
|
||||
it will be detected on USB2 hub `1` or `3`.
|
||||
Regardless of USB2/USB3 connection type, blue sockets are always port `1`,
|
||||
and black sockets are always port `2`.
|
||||
|
||||
Each of 4 USB onboard hubs advertises as supporting per-port power switching, but this is not true.
|
||||
In reality, Raspberry Pi 5 all 4 ports are ganged together in one group,
|
||||
despite belonging to 4 different logical USB hubs.
|
||||
|
||||
To turn off VBUS power it has to be disabled across all onboard hubs and ports with:
|
||||
|
||||
```
|
||||
uhubctl -l 1 -a 0
|
||||
uhubctl -l 3 -a 0
|
||||
```
|
||||
|
||||
To turn it back on:
|
||||
|
||||
```
|
||||
uhubctl -l 1 -a 1
|
||||
uhubctl -l 3 -a 1
|
||||
```
|
||||
|
||||
Note that VBUS power goes down only if all ports are off -
|
||||
enabling any single port enables VBUS back for all 4 ports.
|
||||
|
||||
Notable projects using uhubctl
|
||||
==============================
|
||||
| Project | Description |
|
||||
|:---------------------------------------------------------|:------------------------------------------------------|
|
||||
| [Morse code USB light](https://git.io/fj1F4) | Flash a message in Morse code with USB light |
|
||||
| [Webcam USB light](https://git.io/fj1FB) | Turn on/off LED when webcam is turned on/off |
|
||||
| [Cinema Lightbox](https://goo.gl/fjCvkz) | Turn on/off Cinema Lightbox from iOS Home app |
|
||||
| [Build Status Light](https://goo.gl/3GA82o) | Create a build status light in under 10 minutes |
|
||||
| [Buildenlights](https://git.io/fj1FC) | GitLab/GitHub project build status as green/red light |
|
||||
| [Weather Station](https://goo.gl/3b1FzC) | Reset Weather Station when it freezes |
|
||||
| [sysmoQMOD](https://bit.ly/2VtWrVt) | Reset cellular modems when necessary |
|
||||
| [Smog Sensor](https://bit.ly/2EMwgCk) | Raspberry Pi based smog sensor power reset |
|
||||
| [Terrible Cluster](https://goo.gl/XjiXFu) | Power on/off Raspberry Pi cluster nodes as needed |
|
||||
| [Ideal Music Server](https://bit.ly/39MeVFQ) | Turn off unused USB ports to improve audio quality |
|
||||
| [USB drives with no phantom load](https://goo.gl/qfrmGK) | Power USB drives only when needed to save power |
|
||||
| [USB drive data recovery](https://goo.gl/4MddLr) | Recover data from failing USB hard drive |
|
||||
| [Control power to 3D printer](https://git.io/fh5Tr) | OctoPrint web plugin for USB power control |
|
||||
| [USB fan for Raspberry Pi](https://bit.ly/2TRV6sM) | Control USB fan to avoid Raspberry Pi overheating |
|
||||
| [Raspberry Pi Reboot Router](https://bit.ly/3aNbQqs) | Automatically reboot router if internet isn't working |
|
||||
| [Control USB Lamp With Voice](https://bit.ly/2VtW2SX) | Voice Control of USB Lamp using Siri and Raspberry Pi |
|
||||
| [Control USB LED Strip](https://bit.ly/3oVWfeZ) | Controlling USB powered LED Light Strip |
|
||||
| [Brew beer with Raspberry Pi](https://git.io/JtbLd) | Automated beer brewing system using Raspberry Pi |
|
||||
| [Webcam On-Air Sign](https://bit.ly/3witNsa) | Automatically light up a sign when webcam is in use |
|
||||
| [Do it yourself PPPS](https://git.io/J3lHs) | Solder wires in your USB hub to support uhubctl |
|
||||
| [Python Wrapper for uhubctl](https://github.com/nbuchwitz/python3-uhubctl) | Module to use uhubctl with Python |
|
||||
| Project | Description |
|
||||
|:---------------------------------------------------------|:--------------------------------------------------------|
|
||||
| [Morse code USB light](https://git.io/fj1F4) | Flash a message in Morse code with USB light |
|
||||
| [Webcam USB light](https://git.io/fj1FB) | Turn on/off LED when webcam is turned on/off |
|
||||
| [Cinema Lightbox](https://goo.gl/fjCvkz) | Turn on/off Cinema Lightbox from iOS Home app |
|
||||
| [Build Status Light](https://goo.gl/3GA82o) | Create a build status light in under 10 minutes |
|
||||
| [Buildenlights](https://git.io/fj1FC) | GitLab/GitHub project build status as green/red light |
|
||||
| [Weather Station](https://goo.gl/3b1FzC) | Reset Weather Station when it freezes |
|
||||
| [sysmoQMOD](https://bit.ly/2VtWrVt) | Reset cellular modems when necessary |
|
||||
| [Smog Sensor](https://bit.ly/2EMwgCk) | Raspberry Pi based smog sensor power reset |
|
||||
| [Terrible Cluster](https://goo.gl/XjiXFu) | Power on/off Raspberry Pi cluster nodes as needed |
|
||||
| [Ideal Music Server](https://bit.ly/39MeVFQ) | Turn off unused USB ports to improve audio quality |
|
||||
| [USB drives with no phantom load](https://goo.gl/qfrmGK) | Power USB drives only when needed to save power |
|
||||
| [USB drive data recovery](https://goo.gl/4MddLr) | Recover data from failing USB hard drive |
|
||||
| [Control power to 3D printer](https://git.io/fh5Tr) | OctoPrint web plugin for USB power control |
|
||||
| [USB fan for Raspberry Pi](https://bit.ly/2TRV6sM) | Control USB fan to avoid Raspberry Pi overheating |
|
||||
| [Raspberry Pi Reboot Router](https://bit.ly/3aNbQqs) | Automatically reboot router if internet isn't working |
|
||||
| [Control USB Lamp With Voice](https://bit.ly/2VtW2SX) | Voice Control of USB Lamp using Siri and Raspberry Pi |
|
||||
| [Control USB LED Strip](https://bit.ly/3oVWfeZ) | Controlling USB powered LED Light Strip |
|
||||
| [Brew beer with Raspberry Pi](https://git.io/JtbLd) | Automated beer brewing system using Raspberry Pi |
|
||||
| [Webcam On-Air Sign](https://bit.ly/3witNsa) | Automatically light up a sign when webcam is in use |
|
||||
| [Do it yourself PPPS](https://git.io/J3lHs) | Solder wires in your USB hub to support uhubctl |
|
||||
| [Open source PPPS hub](https://tinyurl.com/yckhystt) | Open source hardware project for uhubctl compatible hub |
|
||||
| [Python Wrapper for uhubctl](https://github.com/nbuchwitz/python3-uhubctl) | Module to use uhubctl with Python |
|
||||
| [labgrid](https://github.com/labgrid-project/labgrid) | Framework for testing embedded Linux on hardware |
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
Copyright (C) 2009-2022 Vadim Mikhailov
|
||||
Copyright (C) 2009-2024 Vadim Mikhailov
|
||||
|
||||
This file can be distributed under the terms and conditions of the
|
||||
GNU General Public License version 2.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# uhubctl – USB hub per-port power control https://github.com/mvp/uhubctl
|
||||
#
|
||||
# Copyright (c) 2009-2022, Vadim Mikhailov
|
||||
# Copyright (c) 2009-2024, Vadim Mikhailov
|
||||
#
|
||||
# This file can be distributed under the terms and conditions of the
|
||||
# GNU General Public License version 2.
|
||||
@@ -16,9 +16,9 @@
|
||||
# sudo usermod -a -G dialout $USER
|
||||
|
||||
# This is for Linux before 6.0:
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0664", GROUP="dialout"
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", MODE="0664", GROUP="dialout"
|
||||
|
||||
# This is for Linux 6.0 or later (ok to keep this block present for older Linux kernels):
|
||||
SUBSYSTEM=="usb", DRIVER=="hub", \
|
||||
SUBSYSTEM=="usb", DRIVER=="usb", \
|
||||
RUN+="/bin/sh -c \"chown -f root:dialout $sys$devpath/*-port*/disable || true\"" \
|
||||
RUN+="/bin/sh -c \"chmod -f 660 $sys$devpath/*-port*/disable || true\""
|
||||
|
||||
93
uhubctl.c
93
uhubctl.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2022 Vadim Mikhailov
|
||||
* Copyright (c) 2009-2024 Vadim Mikhailov
|
||||
*
|
||||
* Utility to turn USB port power on/off
|
||||
* for USB hubs that support per-port power switching.
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(_WIN32)
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_WIN32)
|
||||
#include <libusb.h>
|
||||
#else
|
||||
#include <libusb-1.0/libusb.h>
|
||||
@@ -47,7 +47,7 @@ int snprintf(char * __restrict __str, size_t __size, const char * __restrict __f
|
||||
#include <time.h> /* for nanosleep */
|
||||
#endif
|
||||
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
#include <fcntl.h> /* for open() / O_WRONLY */
|
||||
#endif
|
||||
|
||||
@@ -80,6 +80,7 @@ void sleep_ms(int milliseconds)
|
||||
#define POWER_ON 1
|
||||
#define POWER_CYCLE 2
|
||||
#define POWER_TOGGLE 3
|
||||
#define POWER_FLASH 4
|
||||
|
||||
#define MAX_HUB_CHAIN 8 /* Per USB 3.0 spec max hub chain is 7 */
|
||||
|
||||
@@ -226,14 +227,14 @@ static int opt_exact = 0; /* exact location match - disable USB3 duality handl
|
||||
static int opt_reset = 0; /* reset hub after operation(s) */
|
||||
static int opt_force = 0; /* force operation even on unsupported hubs */
|
||||
static int opt_nodesc = 0; /* skip querying device description */
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
static int opt_nosysfs = 0; /* don't use the Linux sysfs port disable interface, even if available */
|
||||
#endif
|
||||
|
||||
|
||||
static const char short_options[] =
|
||||
"l:L:n:a:p:d:r:w:s:hvefRN"
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
"S"
|
||||
#endif
|
||||
;
|
||||
@@ -251,7 +252,7 @@ static const struct option long_options[] = {
|
||||
{ "exact", no_argument, NULL, 'e' },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "nodesc", no_argument, NULL, 'N' },
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
{ "nosysfs", no_argument, NULL, 'S' },
|
||||
#endif
|
||||
{ "reset", no_argument, NULL, 'R' },
|
||||
@@ -261,7 +262,7 @@ static const struct option long_options[] = {
|
||||
};
|
||||
|
||||
|
||||
static int print_usage()
|
||||
static int print_usage(void)
|
||||
{
|
||||
printf(
|
||||
"uhubctl: utility to control USB port power for smart hubs.\n"
|
||||
@@ -269,18 +270,18 @@ static int print_usage()
|
||||
"Without options, show status for all smart hubs.\n"
|
||||
"\n"
|
||||
"Options [defaults in brackets]:\n"
|
||||
"--action, -a - action to off/on/cycle/toggle (0/1/2/3) for affected ports.\n"
|
||||
"--action, -a - action to off/on/cycle/toggle/flash (0/1/2/3/4) for affected ports.\n"
|
||||
"--ports, -p - ports to operate on [all hub ports].\n"
|
||||
"--location, -l - limit hub by location [all smart hubs].\n"
|
||||
"--level -L - limit hub by location level (e.g. a-b.c is level 3).\n"
|
||||
"--vendor, -n - limit hub by vendor id [%s] (partial ok).\n"
|
||||
"--search, -s - limit hub by attached device description.\n"
|
||||
"--delay, -d - delay for cycle action [%g sec].\n"
|
||||
"--delay, -d - delay for cycle/flash action [%g sec].\n"
|
||||
"--repeat, -r - repeat power off count [%d] (some devices need it to turn off).\n"
|
||||
"--exact, -e - exact location (no USB3 duality handling).\n"
|
||||
"--force, -f - force operation even on unsupported hubs.\n"
|
||||
"--nodesc, -N - do not query device description (helpful for unresponsive devices).\n"
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
"--nosysfs, -S - do not use the Linux sysfs port disable interface.\n"
|
||||
#endif
|
||||
"--reset, -R - reset hub after each power-on action, causing all devices to reassociate.\n"
|
||||
@@ -404,7 +405,7 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
|
||||
return rc;
|
||||
if (desc.bDeviceClass != LIBUSB_CLASS_HUB)
|
||||
return LIBUSB_ERROR_INVALID_PARAM;
|
||||
int bcd_usb = libusb_le16_to_cpu(desc.bcdUSB);
|
||||
int bcd_usb = desc.bcdUSB;
|
||||
int desc_type = bcd_usb >= USB_SS_BCD ? LIBUSB_DT_SUPERSPEED_HUB
|
||||
: LIBUSB_DT_HUB;
|
||||
rc = libusb_open(dev, &devh);
|
||||
@@ -427,8 +428,8 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
|
||||
snprintf(
|
||||
info->vendor, sizeof(info->vendor),
|
||||
"%04x:%04x",
|
||||
libusb_le16_to_cpu(desc.idVendor),
|
||||
libusb_le16_to_cpu(desc.idProduct)
|
||||
desc.idVendor,
|
||||
desc.idProduct
|
||||
);
|
||||
|
||||
/* Convert bus and ports array into USB location string */
|
||||
@@ -490,6 +491,32 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
|
||||
lpsm = HUB_CHAR_INDV_PORT_LPSM;
|
||||
}
|
||||
info->lpsm = lpsm;
|
||||
|
||||
/* Raspberry Pi 5 hack */
|
||||
|
||||
/* TODO: make this hack more reliable by querying Raspberry Pi model */
|
||||
|
||||
if (strlen(info->container_id)==0 &&
|
||||
info->lpsm==HUB_CHAR_INDV_PORT_LPSM &&
|
||||
info->pn_len==0)
|
||||
{
|
||||
/* USB2 */
|
||||
if (strcasecmp(info->vendor, "1d6b:0002")==0 &&
|
||||
info->nports==2 &&
|
||||
!info->super_speed &&
|
||||
(info->bus==1 || info->bus==3))
|
||||
{
|
||||
strcpy(info->container_id, "Raspberry Pi 5 Fake Container Id");
|
||||
}
|
||||
/* USB3 */
|
||||
if (strcasecmp(info->vendor, "1d6b:0003")==0 &&
|
||||
info->nports==1 &&
|
||||
info->super_speed &&
|
||||
(info->bus==2 || info->bus==4))
|
||||
{
|
||||
strcpy(info->container_id, "Raspberry Pi 5 Fake Container Id");
|
||||
}
|
||||
}
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = len;
|
||||
@@ -524,11 +551,11 @@ static int get_port_status(struct libusb_device_handle *devh, int port)
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
return ust.wPortStatus;
|
||||
return libusb_le16_to_cpu(ust.wPortStatus);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
/*
|
||||
* Try to use the Linux sysfs interface to power a port off/on.
|
||||
* Returns 0 on success.
|
||||
@@ -548,10 +575,17 @@ static int set_port_status_linux(struct libusb_device_handle *devh, struct hub_i
|
||||
* The "disable" sysfs interface is available only starting with kernel version 6.0.
|
||||
* For earlier kernel versions the open() call will fail and we fall back to using libusb.
|
||||
*/
|
||||
snprintf(disable_path, PATH_MAX,
|
||||
"/sys/bus/usb/devices/%s:%d.0/%s-port%i/disable",
|
||||
hub->location, configuration, hub->location, port
|
||||
);
|
||||
if (hub->pn_len == 0) {
|
||||
snprintf(disable_path, PATH_MAX,
|
||||
"/sys/bus/usb/devices/%s-0:%d.0/usb%s-port%i/disable",
|
||||
hub->location, configuration, hub->location, port
|
||||
);
|
||||
} else {
|
||||
snprintf(disable_path, PATH_MAX,
|
||||
"/sys/bus/usb/devices/%s:%d.0/%s-port%i/disable",
|
||||
hub->location, configuration, hub->location, port
|
||||
);
|
||||
}
|
||||
|
||||
int disable_fd = open(disable_path, O_WRONLY);
|
||||
if (disable_fd >= 0) {
|
||||
@@ -621,7 +655,7 @@ static int set_port_status_libusb(struct libusb_device_handle *devh, int port, i
|
||||
|
||||
static int set_port_status(struct libusb_device_handle *devh, struct hub_info *hub, int port, int on)
|
||||
{
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
if (!opt_nosysfs) {
|
||||
if (set_port_status_linux(devh, hub, port, on) == 0) {
|
||||
return 0;
|
||||
@@ -662,8 +696,8 @@ static int get_device_description(struct libusb_device * dev, struct descriptor_
|
||||
if (rc)
|
||||
return rc;
|
||||
bzero(ds, sizeof(*ds));
|
||||
id_vendor = libusb_le16_to_cpu(desc.idVendor);
|
||||
id_product = libusb_le16_to_cpu(desc.idProduct);
|
||||
id_vendor = desc.idVendor;
|
||||
id_product = desc.idProduct;
|
||||
rc = libusb_open(dev, &devh);
|
||||
if (rc == 0) {
|
||||
if (!opt_nodesc) {
|
||||
@@ -685,6 +719,7 @@ static int get_device_description(struct libusb_device * dev, struct descriptor_
|
||||
}
|
||||
if (desc.bDeviceClass == LIBUSB_CLASS_HUB) {
|
||||
struct hub_info info;
|
||||
bzero(&info, sizeof(info));
|
||||
rc = get_hub_info(dev, &info);
|
||||
if (rc == 0) {
|
||||
const char * lpsm_type;
|
||||
@@ -823,7 +858,7 @@ static int print_port_status(struct hub_info * hub, int portmask)
|
||||
* In case of error returns negative error code.
|
||||
*/
|
||||
|
||||
static int usb_find_hubs()
|
||||
static int usb_find_hubs(void)
|
||||
{
|
||||
struct libusb_device *dev;
|
||||
int perm_ok = 1;
|
||||
@@ -1011,7 +1046,7 @@ static int usb_find_hubs()
|
||||
}
|
||||
}
|
||||
if (perm_ok == 0 && hub_phys_count == 0) {
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr,
|
||||
"There were permission problems while accessing USB.\n"
|
||||
@@ -1078,6 +1113,9 @@ int main(int argc, char *argv[])
|
||||
if (!strcasecmp(optarg, "toggle") || !strcasecmp(optarg, "3")) {
|
||||
opt_action = POWER_TOGGLE;
|
||||
}
|
||||
if (!strcasecmp(optarg, "flash") || !strcasecmp(optarg, "4")) {
|
||||
opt_action = POWER_FLASH;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
opt_delay = atof(optarg);
|
||||
@@ -1091,7 +1129,7 @@ int main(int argc, char *argv[])
|
||||
case 'N':
|
||||
opt_nodesc = 1;
|
||||
break;
|
||||
#ifdef __gnu_linux__
|
||||
#if defined(__gnu_linux__) || defined(__linux__)
|
||||
case 'S':
|
||||
opt_nosysfs = 1;
|
||||
break;
|
||||
@@ -1193,6 +1231,9 @@ int main(int argc, char *argv[])
|
||||
/* will operate on these ports */
|
||||
int ports = ((1 << hubs[i].nports) - 1) & opt_ports;
|
||||
int should_be_on = k;
|
||||
if (opt_action == POWER_FLASH) {
|
||||
should_be_on = !should_be_on;
|
||||
}
|
||||
|
||||
int port;
|
||||
for (port=1; port <= hubs[i].nports; port++) {
|
||||
@@ -1232,7 +1273,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
libusb_close(devh);
|
||||
}
|
||||
if (k == 0 && opt_action == POWER_CYCLE)
|
||||
if (k == 0 && (opt_action == POWER_CYCLE || opt_action == POWER_FLASH))
|
||||
sleep_ms((int)(opt_delay * 1000));
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
Reference in New Issue
Block a user