62 Commits

Author SHA1 Message Date
mvp
20276ad5ce Release version 2.5.0 2022-11-01 20:26:08 -07:00
mvp
914060b4b5 Add simpler way to configure udev rules and ready to use udev rule file
It turns out that we can allow udev access to any USB hub using DRIVER=="hub"
udev filter, this should make it easier for linux ditros to add proper udev rules.

This change adds more documentation to README, and also adds ready to use udev rule
that should work for any USB hub and any Linux kernel version.
2022-11-01 20:19:00 -07:00
gfrancesco
5a46019e15 ADD: BenQ PD3220U monitor to compatibility list (#464) 2022-10-26 22:55:09 -07:00
Vadim Mikhailov
b6189d1409 Consistently use only C style comments 2022-10-05 12:04:56 -07:00
Vadim Mikhailov
554a5c7eb3 Note that PR #450 has fixed few annoyances listed in FAQ 2022-09-22 16:22:09 -07:00
Vadim Mikhailov
732ad2d90e Fix crash on non-Linux if -S is used
Also move short options near long options table so it is easier to maintain.
2022-09-22 11:24:32 -07:00
Vadim Mikhailov
dd5ff8f79d Fix unused variable compilation warning on non Linux platforms 2022-09-22 11:09:24 -07:00
mvp
a802fa75aa Merge pull request #450 from hnez/linux-sysfs
Use sysfs interface on recent Linux kernels
2022-09-22 11:05:23 -07:00
Leonard Göhrs
24e1540006 Add udev rules for Linux sysfs power switching to README.md
The udev rules for the sysfs case are a bit more complex than those for the
libusb based interface, as udev has built-in support for changing permissions
on device files but not for sysfs attributes.
Instead we have to use chmod / chown to set permissions and owners.

You may notice the " || true" parts in the RUN part of the rules in addition
to the -f parameters. These are there to make sure that no error is logged by
udev even if the disable attribute does not exist. chmod/chown still return
an error exit code even with -f if the requested path does not exist.
" || true" makes sure this error is not propagated to udev.

Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
2022-09-22 11:40:03 +02:00
Leonard Göhrs
aa7fc0a126 Add support for Linux sysfs based power switching
Starting with Linux kernel 6.0[1] there will be a sysfs interface to power USB
ports off/on from userspace.
Try to use this interface before falling back to the usual libusb based
power switching (e.g. when running on a kernel <6.0 or if file permissions do
not allow using the sysfs interface).

The main benefit of using the sysfs interface is that the kernel does not get
confused about the state of a port, so retrying should no longer be required.

[1]: https://lore.kernel.org/all/20220607114522.3359148-1-m.grzeschik@pengutronix.de/

Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
2022-09-22 11:40:03 +02:00
Vadim Mikhailov
7099809b24 Add Apple Pro Display XDR as compatible device
Closes #453.
2022-09-06 18:03:10 -07:00
mvp
a1bc86824b Add Inateck HB2025A as compatible device
This works only if connected via USB2.

Closes #451.
2022-09-05 10:46:29 -07:00
Leonard Göhrs
9d66811175 Split out port status setting logic into separate function
Split out current libusb based power on/off logic into a separate function
in anticipation of a other power switching implementations.

Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
2022-09-02 12:28:04 +02:00
Vadim Mikhailov
9171fc6bad Fix description for j5create JUH470 quirks 2022-09-01 22:35:15 -07:00
Vadim Mikhailov
d75b10d696 Fixed USB version for few supported devices to match their spec
Per USB 3.2 spec, any USB 3.x device can claim itself as USB 3.2 per following table:

| Old style USB version | USB 3.2 specification | Speed, gbps |
|-----------------------|-----------------------|-------------|
| USB 3.0               | USB 3.2 Gen 1         | 5           |
| USB 3.1               | USB 3.2 Gen 2         | 10          |
| USB 3.2               | USB 3.2 Gen 2x2       | 20          |

https://www.usb.org/sites/default/files/usb_3_2_language_product_and_packaging_guidelines_final.pdf

And this is what happens - some devices claim themselves to be USB 3.2 despite only supporting 5 or 10 gbps -
and unfortunately this is correct per USB 3.2 spec. But it is very confusing for people shopping for better product.

Not ideal solution, but a workaround is to use old style USB version designators in our compatibility table
so people do not choose USB 3.2 device listed if it cannot support speeds higher than 5 gbps.

Closes #447.
2022-08-31 15:58:13 -07:00
Tim Ruffing
88e5641fe1 Make sure option strings are null-terminated 2022-08-24 15:59:01 -07:00
Nicolai
b51b5addee Add python3-uhubctl to project list
Add python3-uhubctl to project list
2022-08-24 12:04:15 -07:00
Vadim Mikhailov
a76f45f377 Remove D-Link DUB-H4 rev B from the list
D-Link DUB-H4 rev B does not seem to support VBUS off, remove from supported list.
Closes #440.
2022-08-24 12:02:24 -07:00
mvp
941e356c24 Add HP USB-C Dock G5 as compatible device
Closes #441.
2022-08-22 14:58:56 -07:00
Vadim Mikhailov
e1e4d45066 Add Rosonway RSH-A13 as compatible device
This works only if connected via USB2.

Closes #434.
2022-08-05 11:03:34 -07:00
Vadim Mikhailov
9263ab266e Add Dell U3419W as compatible device
Closes #435.
2022-08-02 09:38:58 -07:00
Vadim Mikhailov
54248b8f29 Note that issue #419 is fixed in MacOS 12.5
Closes #419.
2022-07-20 16:47:09 -07:00
Vadim Mikhailov
06e7240db6 Add Seeed Studio reTerminal CM4104032 as compatible device
Closes #429.
2022-07-12 15:57:28 -07:00
Vadim Mikhailov
e1709c7b62 Add a note for AmazonBasics HU9002V1EBL
Closes #428.
2022-07-12 15:51:48 -07:00
Vadim Mikhailov
38ff03200d Add Rosonway RSH-A13 as compatible device (with some caveats)
Closes #423.
2022-07-01 17:17:45 -07:00
Vadim Mikhailov
24e3680c4b Add a warning that libusb (and uhubctl) are broken on MacOS 12.4 and later
Highlight issue #419 and https://github.com/libusb/libusb/issues/1156.
2022-06-20 11:56:44 -07:00
Vadim Mikhailov
5418edf9d1 Add a warning link that RSHTech RSH-A16 may not work
Rosonway RSH-A16 works, while RSHTech RSH-A16 may not.
Closes #417.
2022-06-17 17:55:52 -07:00
Vadim Mikhailov
a6159d68e7 Add NVidia Jetson Xavier NX as compatible device
Closes #420.
2022-05-27 13:24:16 -07:00
Vadim Mikhailov
ee98e43a43 Update copyright year 2022-05-10 18:13:08 -07:00
Vadim Mikhailov
4f38fde9da Add LG Electronics 27UK850-W monitor as compatible device
Closes #414.
2022-05-10 18:11:25 -07:00
Vadim Mikhailov
a022e60112 Add Lenovo ThinkPlus 4X90W86497 as compatible device
Closes #414.
2022-05-10 18:04:25 -07:00
Vadim Mikhailov
a0f8c87e08 Add Rosonway RSH-518C as compatible device
Closes #407.
2022-05-10 16:25:22 -07:00
Vadim Mikhailov
6f1c71d5a5 Add j5create JUH377 as compatible device
Closes #406.
2022-03-07 10:25:19 -08:00
Vadim Mikhailov
7496d53f87 Add a note for Cypress CY4608 HX2VL
Closes #404.
2022-03-07 10:10:33 -08:00
Vadim Mikhailov
56ea37fc46 Add a warning that some revisions of Bytecc BT-UH340 may not work
Closes #401.
2022-02-28 15:41:08 -08:00
Vadim Mikhailov
ed27158c11 Add Lenovo T24i-10 as compatible device
Closes #384.
2022-02-02 20:22:07 -08:00
Vadim Mikhailov
53fd1f39ce Remove StarTech ST4300USB3 from compatible list, does not seem to properly support VBUS off
Closes #390.
2022-02-01 17:16:22 -08:00
Vadim Mikhailov
950fce2325 Add Centech CT-USB4HUB as compatible device
Closes #393.
2022-02-01 17:13:50 -08:00
Mark Furland
61187d755c Add pluggable USB3-HUB7BC; note USB3-HUB7-81x is 2 port only
Closes #378.
2021-12-17 13:10:32 -08:00
Vadim Mikhailov
610e85ff2d Add StarTech ST4300USB3 as compatible device
Closes #376.
2021-11-29 11:22:47 -08:00
Vadim Mikhailov
5779054ccc Add a note about D-Link DUB-H7 rev. G not supported
Closes #377.
2021-11-29 11:16:41 -08:00
Vadim Mikhailov
f8cb89f4be Add option --nodesc to skip querying device string descriptors
Sometimes target devices may become unresponsive for control messages to read string descriptors.
Option --nodesc (-N) allows to still reset such devices.

Also, as preventative measure, check if libusb_get_string_descriptor_ascii returns any error,
then stop querying any other string descriptor from the same device.
2021-10-29 11:49:59 -07:00
Vadim Mikhailov
1a7d34780f Add Microchip EVB-USB5807 as compatible device
Closes #369.
2021-10-20 16:56:31 -07:00
Vadim Mikhailov
f6e99bc35d Add HP P5Q58UT and LG 27MD5KL-B as compatible devices
Adding two devices reported by @alanzchen in #366.
2021-10-18 22:20:00 -07:00
Vadim Mikhailov
db3ae900d8 Add BenQ PD2700U as compatible device
Closes #362.
2021-09-28 19:15:13 -07:00
Vadim Mikhailov
75b1f668f9 Add Anker AK-A83650A1 as compatible device
Closes #361.
2021-09-28 19:15:08 -07:00
Vadim Mikhailov
37f494ff31 Update UUGear MEGA4 info 2021-08-12 13:33:05 -07:00
Vadim Mikhailov
bc80baa9e9 Add UUGear MEGA4 as compatible device
Add UUGear MEGA4 USB 3.1 PPPS hub for Raspberry PI 4B to supported list,
it was specifically designed to support uhubctl in #316.
https://www.uugear.com/news/new-product-mega4-usb-3-1-ppps-hub-for-raspberry-pi-4
2021-08-09 09:57:41 -07:00
Vadim Mikhailov
6cd357e150 Remove UNITEK Y-3098ABK from supported list
Too many reports in #352 stating it is not supporting VBUS.
2021-08-09 09:32:34 -07:00
Vadim Mikhailov
5ba647ee27 Add Unitek Y-3098ABK as compatible device
Closes #352.
2021-07-07 13:26:55 -07:00
Vadim Mikhailov
69c444b75d Add Hardkernel ODROID-C4 as compatible device
Closes #348.
2021-05-31 20:31:10 -07:00
Vadim Mikhailov
f20007e25e Add Delock 62537 as compatible device
Closes #346.
2021-05-17 22:08:47 -07:00
Vadim Mikhailov
46d0de4331 Re-add Delock 87445 to supported list
It seems to work after all (originally reported in #107, then removed in #123).
It looks like there are different hardware revisions, some work well, some are not detected - added a note.
2021-05-17 22:04:11 -07:00
Vadim Mikhailov
23c15ffcf8 Add diyppps to notable projects
Closes #343.
2021-05-01 22:13:32 -07:00
Vadim Mikhailov
16f7a6dd23 Add AmazonBasics HUC9002V1ESL as compatible device
AmazonBasics HUC900xxx models seem to be identical to HU900xxx except for included USB-C cable.
2021-05-01 22:05:42 -07:00
Vadim Mikhailov
7bafc7ffb3 Add a note for Linksys USB2HUB4
Closes #331.
2021-04-02 14:27:53 -07:00
Vadim Mikhailov
0a42b91382 Add Webcam On-Air Sign to notable projects 2021-04-01 09:42:04 -07:00
Vadim Mikhailov
2820f9fa27 DLink DUB-H4 rev B4 does not work
Closes #328.
2021-03-29 15:48:24 -07:00
Vadim Mikhailov
fb85325629 Add AmazonBasics U3-7HUB as supported device
AmazonBasics U3-7HUB power switching works, but only on 1 charge port with lightning symbol.
This should also work for similar AmazonBasics hubs U3-4HUB and U3-10HUB.

Closes #325.
2021-03-18 17:02:38 -07:00
Vadim Mikhailov
e5ae7b9906 Add Plugable USB3-HUB10-C2 as supported device
Plugable USB3-HUB10-C2 power switching works, but only on 2 charge ports.
This is also true for USB3-HUB7C, updated note accordingly.

Closes #322.
2021-03-05 12:55:00 -08:00
Vadim Mikhailov
bf3971423a Add Autobrew to list of notable projects 2021-03-05 12:46:04 -08:00
Vadim Mikhailov
7757db54ac Release version 2.4.0 as stable brew tap 2021-02-13 16:48:24 -08:00
7 changed files with 275 additions and 69 deletions

4
.gitignore vendored
View File

@@ -6,3 +6,7 @@ uhubctl
# Mac symbols
*.dSYM
# Patches
*.patch
*.diff

View File

@@ -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.3.0.tar.gz"
sha256 "714f733592d3cb6ba8efc84fbc03b1beed2323918ff33aef01cdb956755be7b7"
url "https://github.com/mvp/uhubctl/archive/v2.4.0.tar.gz"
sha256 "391f24fd1f89cacce801df38ecc289b34c3627bc08ee69eec515af7e1a283d97"
license "GPL-2.0"
depends_on "libusb"

View File

@@ -1,6 +1,6 @@
uhubctl USB hub per-port power control.
Copyright (c) 2009-2020, Vadim Mikhailov
Copyright (c) 2009-2022, 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

View File

@@ -20,10 +20,13 @@ This is list of known compatible USB hubs:
|:-------------------|:-----------------------------------------------------|:------|:----|:----------|:--------|:-----|
| 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 | 7 | 3.1 |`2109:2817`| 2018 | |
| AmazonBasics | HU9002V1SBL, HU9002V1ESL | 10 | 3.1 |`2109:2817`| 2018 | |
| 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 | Z87-PLUS Motherboard (onboard USB hub) | 4 | 3.0 | | 2013 | 2016 |
@@ -32,55 +35,78 @@ This is list of known compatible USB hubs:
| B+B SmartWorx | USH304 | 4 | 3.0 |`04B4:6506`| 2017 | |
| 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 | |
| BenQ | PD3220U | 4 | 3.1 |`05E3:0610`| 2019 | |
| Buffalo | BSH4A05U3BK | 4 | 3.0 |`05E3:0610`| 2015 | |
| Bytecc | BT-UH340 | 4 | 3.0 |`2109:8110`| 2010 | |
| 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 | |
| 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 | |
| Cypress | CY4608 HX2VL development kit | 4 | 2.0 |`04B4:6570`| 2012 | |
| D-Link | DUB-H4 rev B (silver). Note: rev B7+ not supported | 4 | 2.0 |`05E3:0605`| 2005 | 2010 |
| 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). Note: rev B,C,F not supported| 7 | 2.0 |`05E3:0608`| 2012 | |
| 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 | 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 | |
| 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 | |
| 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 |
| Hewlett Packard | USB-C Dock G5 5TW10AA | 5 | 3.0 |`03F0:076B`| 2019 | |
| Hewlett Packard | P5Q58UT | 3 | 3.0 | | 2019 | |
| Inateck | HB2025A ([USB2 only](https://bit.ly/3wXF5UO)) | 4 | 3.1 |`2109:2822`| 2021 | |
| IOI | U3H415E1 | 4 | 3.0 | | 2012 | |
| j5create | JUH470 (works only in USB2 mode) | 3 | 3.0 |`05E3:0610`| 2014 | |
| 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 | |
| LG Electronics | 27UK850-W monitor | 2 | 3.0 | | 2018 | |
| 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 | |
| Lenovo | ThinkPad X200 Ultrabase 42X4963 | 3 | 2.0 |`17EF:1005`| 2008 | 2011 |
| 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 | |
| Lindy | USB serial converter 4 port | 4 | 1.1 |`058F:9254`| 2008 | |
| Linksys | USB2HUB4 | 4 | 2.0 | | 2004 | 2010 |
| Linksys | USB2HUB4 ([note](https://git.io/JYiDZ)) | 4 | 2.0 | | 2004 | 2010 |
| Maplin | A08CQ | 7 | 2.0 |`0409:0059`| 2008 | 2011 |
| Microchip | EVB-USB2517 | 7 | 2.0 | | 2008 | |
| Microchip | EVB-USB2534BC | 4 | 2.0 | | 2013 | |
| Microchip | EVB-USB5807 | 7 | 3.1 | | 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 | |
| Plugable | USB3-HUB7BC | 7 | 3.0 |`2109:0813`| 2015 | |
| Plugable | USB3-HUB7C | 7 | 3.0 |`2109:0813`| 2015 | |
| Plugable | USB3-HUB7-81X | 7 | 3.0 |`2109:0813`| 2012 | |
| 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 | |
| Renesas | uPD720202 PCIe USB 3.0 host controller | 2 | 3.0 | | 2013 | |
| Rosewill | RHUB-210 | 4 | 2.0 |`0409:005A`| 2011 | 2014 |
| Rosonway | RSH-A16 ([note](https://git.io/JTawg)) | 16 | 3.2 |`0bda:0411`| 2020 | |
| Rosonway | RSH-518C ([note](https://bit.ly/3kYZUsA)) | 7 | 3.0 |`2109:0817`| 2021 | |
| 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 | |
| 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 | |
| Sunix | SHB4200MA | 4 | 2.0 |`0409:0058`| 2006 | 2009 |
| 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 | |
This table is by no means complete.
If your hub works with `uhubctl`, but is not listed above, please report it
@@ -112,6 +138,9 @@ 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).
@@ -186,20 +215,35 @@ Linux USB permissions
=====================
On Linux, you should configure `udev` USB permissions (otherwise you will have to run it as root using `sudo uhubctl`).
To fix USB permissions, first run `sudo uhubctl` and note all `vid:pid` for hubs you need to control.
Then, add one or more udev rules like below to file `/etc/udev/rules.d/52-usb.rules` (replace 2001 with your vendor id):
SUBSYSTEM=="usb", ATTR{idVendor}=="2001", MODE="0666"
Starting with Linux Kernel 6.0 there is a standard interface to turn USB hub ports on or off,
and `uhubctl` will try to use it (instead of `libusb`) to set the port status.
This is why there are additional rules for 6.0+ kernels.
There is no harm in having these rules on systems running older kernel versions.
To fix USB permissions, first run `sudo uhubctl` and note all `vid:pid` for hubs you need to control.
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"
# Linux 6.0 or later (its ok to have this block present for older Linux kernels):
SUBSYSTEM=="usb", DRIVER=="hub", \
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:
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", ATTR{idVendor}=="2109", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="1d6b", MODE="0666"
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0666", ATTR{idVendor}=="2109"
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0666", ATTR{idVendor}=="1d6b"
If you don't like wide open mode `0666`, you can restrict access by group like this:
SUBSYSTEM=="usb", ATTR{idVendor}=="2001", MODE="0664", GROUP="dialout"
SUBSYSTEM=="usb", DRIVER=="hub", MODE="0664", GROUP="dialout"
# Linux 6.0 or later (its ok to have this block present for older Linux kernels):
SUBSYSTEM=="usb", DRIVER=="hub", \
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\""
and then add permitted users to `dialout` group:
@@ -209,6 +253,7 @@ For your `udev` rule changes to take effect, reboot or run:
sudo udevadm trigger --attr-match=subsystem=usb
For your convenience, ready to use udev rule is provided [here](https://github.com/mvp/uhubctl/blob/master/udev/rules.d/52-usb.rules).
FAQ
@@ -264,6 +309,8 @@ 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.
@@ -282,6 +329,8 @@ 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 -
@@ -314,6 +363,7 @@ Doing so will confuse internal hub circuitry and will cause unpredictable behavi
This is the limitation of Raspberry Pi hardware design.
As a workaround, you can buy any external USB hub from supported list above,
attach it to any USB port of Raspberry Pi, and control power on its ports independently.
Also, there are supported hubs designed specifically for Raspberry Pi, e.g. UUGear MEGA4.
For reference, supported Raspberry Pi models have following internal USB topology:
@@ -378,12 +428,16 @@ Notable projects using uhubctl
| [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 |
Copyright
=========
Copyright (C) 2009-2020 Vadim Mikhailov
Copyright (C) 2009-2022 Vadim Mikhailov
This file can be distributed under the terms and conditions of the
GNU General Public License version 2.

View File

@@ -1 +1 @@
2.4.0
2.5.0

24
udev/rules.d/52-usb.rules Normal file
View File

@@ -0,0 +1,24 @@
# uhubctl USB hub per-port power control https://github.com/mvp/uhubctl
#
# Copyright (c) 2009-2022, Vadim Mikhailov
#
# This file can be distributed under the terms and conditions of the
# GNU General Public License version 2.
# uhubctl udev rules for rootless operation on Linux for users in group `dialout`.
#
# Copy this file to /etc/udev/rules.d, then reboot or run:
#
# sudo udevadm trigger --attr-match=subsystem=usb
#
# To add yourself to this permission group, run:
#
# sudo usermod -a -G dialout $USER
# This is for Linux before 6.0:
SUBSYSTEM=="usb", DRIVER=="hub", 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", \
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\""

216
uhubctl.c
View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2020 Vadim Mikhailov
* Copyright (c) 2009-2022 Vadim Mikhailov
*
* Utility to turn USB port power on/off
* for USB hubs that support per-port power switching.
@@ -47,6 +47,10 @@ int snprintf(char * __restrict __str, size_t __size, const char * __restrict __f
#include <time.h> /* for nanosleep */
#endif
#ifdef __gnu_linux__
#include <fcntl.h> /* for open() / O_WRONLY */
#endif
/* cross-platform sleep function */
void sleep_ms(int milliseconds)
@@ -221,6 +225,18 @@ static int opt_wait = 20; /* wait before repeating in ms */
static int opt_exact = 0; /* exact location match - disable USB3 duality handling */
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__
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__
"S"
#endif
;
static const struct option long_options[] = {
{ "location", required_argument, NULL, 'l' },
@@ -234,6 +250,10 @@ static const struct option long_options[] = {
{ "wait", required_argument, NULL, 'w' },
{ "exact", no_argument, NULL, 'e' },
{ "force", no_argument, NULL, 'f' },
{ "nodesc", no_argument, NULL, 'N' },
#ifdef __gnu_linux__
{ "nosysfs", no_argument, NULL, 'S' },
#endif
{ "reset", no_argument, NULL, 'R' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
@@ -259,6 +279,10 @@ static int print_usage()
"--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__
"--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"
"--wait, -w - wait before repeat power off [%d ms].\n"
"--version, -v - print program version.\n"
@@ -504,6 +528,113 @@ static int get_port_status(struct libusb_device_handle *devh, int port)
}
#ifdef __gnu_linux__
/*
* Try to use the Linux sysfs interface to power a port off/on.
* Returns 0 on success.
*/
static int set_port_status_linux(struct libusb_device_handle *devh, struct hub_info *hub, int port, int on)
{
int configuration = 0;
char disable_path[PATH_MAX];
int rc = libusb_get_configuration(devh, &configuration);
if (rc < 0) {
return rc;
}
/*
* 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
);
int disable_fd = open(disable_path, O_WRONLY);
if (disable_fd >= 0) {
rc = write(disable_fd, on ? "0" : "1", 1);
close(disable_fd);
}
if (disable_fd < 0 || rc < 0) {
/*
* ENOENT is the expected error when running on Linux kernel < 6.0 where
* sysfs disable interface does not exist yet - no need to report anything in this case.
* If the file exists but another error occurs it is most likely a permission issue.
* Print an error message mostly geared towards setting up udev.
*/
if (errno != ENOENT) {
fprintf(stderr,
"Failed to set port status by writing to %s (%s).\n"
"Follow https://git.io/JIB2Z to make sure that udev is set up correctly.\n"
"Falling back to libusb based port control.\n"
"Use -S to skip trying the sysfs interface and printing this message.\n",
disable_path, strerror(errno)
);
}
return -1;
}
return 0;
}
#endif
/*
* Use a control transfer via libusb to turn a port off/on.
* Returns >= 0 on success.
*/
static int set_port_status_libusb(struct libusb_device_handle *devh, int port, int on)
{
int rc = 0;
int request = on ? LIBUSB_REQUEST_SET_FEATURE
: LIBUSB_REQUEST_CLEAR_FEATURE;
int repeat = on ? 1 : opt_repeat;
while (repeat-- > 0) {
rc = libusb_control_transfer(devh,
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_OTHER,
request, USB_PORT_FEAT_POWER,
port, NULL, 0, USB_CTRL_GET_TIMEOUT
);
if (rc < 0) {
perror("Failed to control port power!\n");
}
if (repeat > 0) {
sleep_ms(opt_wait);
}
}
return rc;
}
/*
* Try different methods to power a port off/on.
* Return >= 0 on success.
*/
static int set_port_status(struct libusb_device_handle *devh, struct hub_info *hub, int port, int on)
{
#ifdef __gnu_linux__
if (!opt_nosysfs) {
if (set_port_status_linux(devh, hub, port, on) == 0) {
return 0;
}
}
#else
(void)hub;
#endif
return set_port_status_libusb(devh, port, on);
}
/*
* Get USB device descriptor strings and summary description.
*
@@ -535,20 +666,22 @@ static int get_device_description(struct libusb_device * dev, struct descriptor_
id_product = libusb_le16_to_cpu(desc.idProduct);
rc = libusb_open(dev, &devh);
if (rc == 0) {
if (desc.iManufacturer) {
libusb_get_string_descriptor_ascii(devh,
desc.iManufacturer, (unsigned char*)ds->vendor, sizeof(ds->vendor));
rtrim(ds->vendor);
}
if (desc.iProduct) {
libusb_get_string_descriptor_ascii(devh,
desc.iProduct, (unsigned char*)ds->product, sizeof(ds->product));
rtrim(ds->product);
}
if (desc.iSerialNumber) {
libusb_get_string_descriptor_ascii(devh,
desc.iSerialNumber, (unsigned char*)ds->serial, sizeof(ds->serial));
rtrim(ds->serial);
if (!opt_nodesc) {
if (desc.iManufacturer) {
rc = libusb_get_string_descriptor_ascii(devh,
desc.iManufacturer, (unsigned char*)ds->vendor, sizeof(ds->vendor));
rtrim(ds->vendor);
}
if (rc >= 0 && desc.iProduct) {
rc = libusb_get_string_descriptor_ascii(devh,
desc.iProduct, (unsigned char*)ds->product, sizeof(ds->product));
rtrim(ds->product);
}
if (rc >= 0 && desc.iSerialNumber) {
rc = libusb_get_string_descriptor_ascii(devh,
desc.iSerialNumber, (unsigned char*)ds->serial, sizeof(ds->serial));
rtrim(ds->serial);
}
}
if (desc.bDeviceClass == LIBUSB_CLASS_HUB) {
struct hub_info info;
@@ -899,8 +1032,7 @@ int main(int argc, char *argv[])
int option_index = 0;
for (;;) {
c = getopt_long(argc, argv, "l:L:n:a:p:d:r:w:s:hvefR",
long_options, &option_index);
c = getopt_long(argc, argv, short_options, long_options, &option_index);
if (c == -1)
break; /* no more options left */
switch (c) {
@@ -914,16 +1046,16 @@ int main(int argc, char *argv[])
printf("\n");
break;
case 'l':
strncpy(opt_location, optarg, sizeof(opt_location));
snprintf(opt_location, sizeof(opt_location), "%s", optarg);
break;
case 'L':
opt_level = atoi(optarg);
break;
case 'n':
strncpy(opt_vendor, optarg, sizeof(opt_vendor));
snprintf(opt_vendor, sizeof(opt_vendor), "%s", optarg);
break;
case 's':
strncpy(opt_search, optarg, sizeof(opt_search));
snprintf(opt_search, sizeof(opt_search), "%s", optarg);
break;
case 'p':
if (!strcasecmp(optarg, "all")) { /* all ports is the default */
@@ -956,6 +1088,14 @@ int main(int argc, char *argv[])
case 'f':
opt_force = 1;
break;
case 'N':
opt_nodesc = 1;
break;
#ifdef __gnu_linux__
case 'S':
opt_nosysfs = 1;
break;
#endif
case 'e':
opt_exact = 1;
break;
@@ -1033,7 +1173,7 @@ int main(int argc, char *argv[])
continue;
if (k == 1 && opt_action == POWER_KEEP)
continue;
// if toggle requested, do it only once when `k == 0`
/* if toggle requested, do it only once when `k == 0` */
if (k == 1 && opt_action == POWER_TOGGLE)
continue;
int i;
@@ -1052,45 +1192,29 @@ int main(int argc, char *argv[])
if (rc == 0) {
/* will operate on these ports */
int ports = ((1 << hubs[i].nports) - 1) & opt_ports;
int request = (k == 0) ? LIBUSB_REQUEST_CLEAR_FEATURE
: LIBUSB_REQUEST_SET_FEATURE;
int should_be_on = k;
int port;
for (port=1; port <= hubs[i].nports; port++) {
if ((1 << (port-1)) & ports) {
int port_status = get_port_status(devh, port);
int power_mask = hubs[i].super_speed ? USB_SS_PORT_STAT_POWER
: USB_PORT_STAT_POWER;
int powered_on = port_status & power_mask;
int is_on = (port_status & power_mask) != 0;
if (opt_action == POWER_TOGGLE) {
request = powered_on ? LIBUSB_REQUEST_CLEAR_FEATURE
: LIBUSB_REQUEST_SET_FEATURE;
should_be_on = !is_on;
}
if (k == 0 && !powered_on && opt_action != POWER_TOGGLE)
continue;
if (k == 1 && powered_on)
continue;
int repeat = powered_on ? opt_repeat : 1;
while (repeat-- > 0) {
rc = libusb_control_transfer(devh,
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_OTHER,
request, USB_PORT_FEAT_POWER,
port, NULL, 0, USB_CTRL_GET_TIMEOUT
);
if (rc < 0) {
perror("Failed to control port power!\n");
}
if (repeat > 0) {
sleep_ms(opt_wait);
}
if (is_on != should_be_on) {
rc = set_port_status(devh, &hubs[i], port, should_be_on);
}
}
}
/* USB3 hubs need extra delay to actually turn off: */
if (k==0 && hubs[i].super_speed)
sleep_ms(150);
printf("Sent power %s request\n",
request == LIBUSB_REQUEST_CLEAR_FEATURE ? "off" : "on"
);
printf("Sent power %s request\n", should_be_on ? "on" : "off");
printf("New status for hub %s [%s]\n",
hubs[i].location, hubs[i].ds.description
);