Hello community,

here is the log from the commit of package uhubctl for openSUSE:Factory checked 
in at 2020-12-14 18:09:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/uhubctl (Old)
 and      /work/SRC/openSUSE:Factory/.uhubctl.new.2328 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "uhubctl"

Mon Dec 14 18:09:41 2020 rev:4 rq:855672 version:2.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/uhubctl/uhubctl.changes  2020-05-26 
17:20:46.760163001 +0200
+++ /work/SRC/openSUSE:Factory/.uhubctl.new.2328/uhubctl.changes        
2020-12-14 18:10:14.283691957 +0100
@@ -1,0 +2,10 @@
+Mon Dec 14 06:52:33 UTC 2020 - Martin Hauke <[email protected]>
+
+- Update to version 2.3.0
+  * Much improved USB3 support, in particular for RPi 4B and
+    M1 Macs
+  * Allow forced operation on unsupported hubs - not likely to
+    work though
+  * More supported devices
+
+-------------------------------------------------------------------

Old:
----
  uhubctl-2.2.0.tar.gz

New:
----
  uhubctl-2.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ uhubctl.spec ++++++
--- /var/tmp/diff_new_pack.YNZ5dY/_old  2020-12-14 18:10:15.019692688 +0100
+++ /var/tmp/diff_new_pack.YNZ5dY/_new  2020-12-14 18:10:15.019692688 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           uhubctl
-Version:        2.2.0
+Version:        2.3.0
 Release:        0
 Summary:        USB hub per-port power control
 License:        GPL-2.0-only

++++++ uhubctl-2.2.0.tar.gz -> uhubctl-2.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uhubctl-2.2.0/Formula/uhubctl.rb 
new/uhubctl-2.3.0/Formula/uhubctl.rb
--- old/uhubctl-2.2.0/Formula/uhubctl.rb        2020-05-22 22:39:47.000000000 
+0200
+++ new/uhubctl-2.3.0/Formula/uhubctl.rb        2020-12-13 23:31:05.000000000 
+0100
@@ -1,9 +1,17 @@
 class Uhubctl < Formula
-  desc "control USB hubs powering per-port"
+  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.2.0.tar.gz";
+  sha256 "e5a722cb41967903bedbab4eea566ab332241a7f05fc7bc9c386b9a5e1762d8b"
+  license "GPL-2.0"
 
   depends_on "libusb"
+  depends_on "pkg-config" => :build
+
+  livecheck do
+    url :stable
+  end
 
   def install
     system "make"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uhubctl-2.2.0/Makefile new/uhubctl-2.3.0/Makefile
--- old/uhubctl-2.2.0/Makefile  2020-05-22 22:39:47.000000000 +0200
+++ new/uhubctl-2.3.0/Makefile  2020-12-13 23:31:05.000000000 +0100
@@ -14,34 +14,26 @@
 CC ?= gcc
 CFLAGS ?= -g -O0
 CFLAGS += -Wall -Wextra -std=c99 -pedantic
-GIT_VERSION := $(shell git describe --match "v[0-9]*" --abbrev=8 --dirty 
--always --tags | cut -c2-)
+GIT_VERSION := $(shell git describe --match "v[0-9]*" --abbrev=8 --dirty 
--tags | cut -c2-)
 ifeq ($(GIT_VERSION),)
-    GIT_VERSION := $(shell cat VERSION)
+       GIT_VERSION := $(shell cat VERSION)
 endif
 CFLAGS += -DPROGRAM_VERSION=\"$(GIT_VERSION)\"
 
+# Use hardening options on Linux
 ifeq ($(UNAME_S),Linux)
-       LDFLAGS += -Wl,-zrelro,-znow -lusb-1.0
+       LDFLAGS += -Wl,-zrelro,-znow
 endif
 
-ifeq ($(UNAME_S),Darwin)
-ifneq ($(wildcard /opt/local/include),)
-       # MacPorts
-       CFLAGS  += -I/opt/local/include
-       LDFLAGS += -L/opt/local/lib
-endif
+# Use pkg-config if available
+ifneq (,$(shell which pkg-config))
+       CFLAGS  += $(shell pkg-config --cflags libusb-1.0)
+       LDFLAGS += $(shell pkg-config --libs libusb-1.0)
+else
+# But it should still build if pkg-config is not available (e.g. Linux or Mac 
homebrew)
        LDFLAGS += -lusb-1.0
 endif
 
-ifeq ($(UNAME_S),FreeBSD)
-       LDFLAGS += -lusb
-endif
-
-ifeq ($(UNAME_S),NetBSD)
-    CFLAGS  += $(shell pkg-config --cflags libusb-1.0)
-    LDFLAGS += $(shell pkg-config --libs libusb-1.0)
-endif
-
 PROGRAM = uhubctl
 
 $(PROGRAM): $(PROGRAM).c
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uhubctl-2.2.0/README.md new/uhubctl-2.3.0/README.md
--- old/uhubctl-2.2.0/README.md 2020-05-22 22:39:47.000000000 +0200
+++ new/uhubctl-2.3.0/README.md 2020-12-13 23:31:05.000000000 +0100
@@ -20,8 +20,10 @@
 
|:-------------------|:-----------------------------------------------------|:------|:----|:----------|:--------|:-----|
 | 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       | HU9002V1SBL ([RPi issue](https://goo.gl/CLt46M))     | 
10    | 3.1 |`2109:2817`| 2018    |      |
-| AmazonBasics       | HUC9002V1ESL ([RPi issue](https://goo.gl/CLt46M))    | 
10    | 3.1 |`2109:2817`| 2018    |      |
+| AmazonBasics       | HU9003V1EBL                                          | 
7     | 3.1 |`2109:2817`| 2018    |      |
+| AmazonBasics       | HU9002V1SBL, HU9002V1ESL                             | 
10    | 3.1 |`2109:2817`| 2018    |      |
+| AmazonBasics       | HUC9002V1SBL, HUC9002V1EBL, HUC9002V1ESL             | 
10    | 3.1 |`2109:2817`| 2018    |      |
+| Anker              | AK-68ANHUB-BV7A-0004                                 | 
7     | 3.0 |`2109:0812`| 2014    |      |
 | 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 |
@@ -29,7 +31,6 @@
 | 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 |
-| Belkin             | F5U701-BLK                                           | 
7     | 2.0 |           | 2008    | 2012 |
 | Buffalo            | BSH4A05U3BK                                          | 
4     | 3.0 |`05E3:0610`| 2015    |      |
 | Bytecc             | BT-UH340                                             | 
4     | 3.0 |`2109:8110`| 2010    |      |
 | Circuitco          | Beagleboard-xM (internal USB hub)                    | 
4     | 2.0 |`0424:9514`| 2010    |      |
@@ -37,10 +38,11 @@
 | 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)                                | 
4     | 2.0 |`05E3:0605`| 2005    | 2010 |
-| D-Link             | DUB-H4 rev D,E (black). Note: rev A,C not supported  | 
4     | 2.0 |`05E3:0608`| 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 (black). Note: rev B,C not supported    | 
7     | 2.0 |`05E3:0608`| 2012    |      |
-| Dell               | P2416D 24" QHD Monitor                               | 
4     | 2.0 |           | 2017    |      |
+| D-Link             | DUB-H7 rev D,E (black). Note: rev B,C,F 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    |      |
 | Elecom             | U2H-G4S                                              | 
4     | 2.0 |           | 2006    | 2011 |
@@ -58,7 +60,9 @@
 | Linksys            | USB2HUB4                                             | 
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    |      |
 | Moxa               | Uport-407                                            | 
7     | 2.0 |`110A:0407`| 2009    |      |
+| NVidia             | Jetson Nano B01 ([details](https://git.io/JJaFR))    | 
4     | 3.0 |           | 2019    |      |
 | 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    |      |
@@ -68,9 +72,9 @@
 | 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    |      |
 | Sanwa Supply       | USB-HUB14GPH                                         | 
4     | 1.1 |           | 2001    | 2003 |
 | Seagate            | Backup Plus Hub STEL8000100                          | 
2     | 3.0 |`0BC2:AB44`| 2016    |      |
-| StarTech           | ST4200USBM                                           | 
4     | 2.0 |`0409:005A`| 2004    |      |
 | Sunix              | SHB4200MA                                            | 
4     | 2.0 |`0409:0058`| 2006    | 2009 |
 | Targus             | PAUH212U                                             | 
7     | 2.0 |           | 2004    | 2009 |
 | Texas Instruments  | TUSB4041PAPEVM                                       | 
4     | 2.1 |`0451:8142`| 2015    |      |
@@ -103,46 +107,57 @@
 =========
 
 This utility was tested to compile and work on Linux
-(Ubuntu/Debian, Redhat/Fedora/CentOS, Arch Linux, Gentoo, openSUSE, 
Buildroot), FreeBSD, NetBSD and Mac OS X.
+(Ubuntu/Debian, Redhat/Fedora/CentOS, Arch Linux, Gentoo, openSUSE, 
Buildroot), FreeBSD, NetBSD, SunOS and MacOS.
 
 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).
 This may be fixed if `libusb` starts supporting different driver on Windows.
 
+Note that it is highly recommended to have `pkg-config` installed (many 
platforms provide it by default).
+
 First, you need to install library libusb-1.0 (version 1.0.12 or later, 1.0.16 
or later is recommended):
 
 * Ubuntu: `sudo apt-get install libusb-1.0-0-dev`
 * Redhat: `sudo yum install libusb1-devel`
-* MacOSX: `brew install libusb`, or `sudo port install libusb-devel`
-  > :warning: `libusb-1.0.23` is 
[broken](https://github.com/libusb/libusb/issues/707) on MacOS Catalina!
-  You have to install `libusb-1.0.22` until [libusb issue 
707](https://github.com/libusb/libusb/issues/707) is fixed,
-  or use this workaround to force use of older Mojave build:
-
-      brew uninstall --ignore-dependencies libusb
-      brew install 
https://raw.githubusercontent.com/Homebrew/homebrew-core/5314f1d/Formula/libusb.rb
-
+* MacOS: `brew install libusb`, or `sudo port install libusb-devel`
 * FreeBSD: libusb is included by default
 * NetBSD: `sudo pkgin install libusb1 gmake pkg-config`
 * Windows: TBD?
 
-To fetch uhubctl source:
+To fetch uhubctl source and compile it:
 
     git clone https://github.com/mvp/uhubctl
+    cd uhubctl
+    make
+
+This should generate `uhubctl` binary.
+You can install it in your system as `/usr/sbin/uhubctl` using:
+
+    sudo make install
 
-To compile, simply run `make` - this will generate `uhubctl` binary.
 Note that on some OS (e.g. FreeBSD/NetBSD) you need to use `gmake` instead to 
build.
 
-Also, for Mac OS X you can install `uhubctl` with Homebrew custom tap:
+Also, on MacOS you can install `uhubctl` with all necessary dependencies in 
one shot using Homebrew tap:
 
 ```
 brew tap mvp/uhubctl https://github.com/mvp/uhubctl
-brew install --HEAD uhubctl
+brew install uhubctl
+```
+To build/install from master branch, use `--HEAD`:
+```
+brew install uhubctl --HEAD
 ```
 
 Usage
 =====
 
+> :warning: On Linux, use `sudo` or configure USB permissions as described 
below!
+
+To list all supported hubs:
+
+    uhubctl
+
 You can control the power on a USB port(s) like this:
 
     uhubctl -a off -p 2
@@ -169,10 +184,16 @@
 
 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 with your vendor id):
+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"
 
+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:
+
+    SUBSYSTEM=="usb", ATTR{idVendor}=="2109", MODE="0666"
+    SUBSYSTEM=="usb", ATTR{idVendor}=="1d6b", MODE="0666"
+
 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"
@@ -194,7 +215,8 @@
 
 According to USB 2.0 specification, USB hubs can advertise no power switching,
 ganged (all ports at once) power switching or per-port (individual) power 
switching.
-Note that `uhubctl` will only detect USB hubs which support per-port power 
switching.
+Note that by default `uhubctl` will only detect USB hubs which support 
per-port power switching
+(but you can force it to try operating on unsupported hubs with option `-f`).
 You can find what kind of power switching your hardware supports by using 
`sudo lsusb -v`:
 
 No power switching:
@@ -261,8 +283,11 @@
 `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).
 
-If your device is USB mass storage, invoking `udisksctl` before calling 
`uhubctl`
-might help to mitigate this issue:
+Disabling USB authorization for device in question before turning power off 
with `uhubctl` should help:
+
+    echo 0 > sudo tee /sys/bus/usb/devices/${location}.${port}/authorized
+
+If your device is USB mass storage, invoking `udisksctl` before calling 
`uhubctl` should help too:
 
     sudo udisksctl power-off --block-device /dev/disk/...`
     sudo uhubctl -a off ...
@@ -307,8 +332,9 @@
 
 ##### Raspberry Pi 4B
 
- > :warning: You may need to [update 
firmware](https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md)
-to vl805 00137ac or later to make power switching work on RPi 4B.
+ > :warning: If your VL805 firmware is older than `00137ad` (check with `sudo 
rpi-eeprom-update`),
+you have to [update 
firmware](https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md)
+to make power switching work on RPi 4B.
 
   * USB2 hub `1`, 1 port, only connects hub `1-1` below.
 
@@ -320,9 +346,7 @@
 
         uhubctl -l 2 -a 0
 
-  * USB2 hub `3`, 1 port, OTG controller:
-
-        uhubctl -l 3 -p 1 -a 0
+  * USB2 hub `3`, 1 port, OTG controller. Power switching is [not 
supported](https://git.io/JUc5Q).
 
 
 As a workaround, you can buy any external USB hub from supported list,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uhubctl-2.2.0/VERSION new/uhubctl-2.3.0/VERSION
--- old/uhubctl-2.2.0/VERSION   2020-05-22 22:39:47.000000000 +0200
+++ new/uhubctl-2.3.0/VERSION   2020-12-13 23:31:05.000000000 +0100
@@ -1 +1 @@
-v2.2.0-dev
+2.3.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uhubctl-2.2.0/uhubctl.c new/uhubctl-2.3.0/uhubctl.c
--- old/uhubctl-2.2.0/uhubctl.c 2020-05-22 22:39:47.000000000 +0200
+++ new/uhubctl-2.3.0/uhubctl.c 2020-12-13 23:31:05.000000000 +0100
@@ -188,13 +188,16 @@
 struct hub_info {
     struct libusb_device *dev;
     int bcd_usb;
+    int super_speed; /* 1 if super speed hub, and 0 otherwise */
     int nports;
-    int ppps;
+    int lpsm; /* logical power switching mode */
     int actionable; /* true if this hub is subject to action */
     char container_id[33]; /* container ID as hex string */
     char vendor[16];
     char location[32];
-    int level;
+    uint8_t bus;
+    uint8_t port_numbers[MAX_HUB_CHAIN];
+    int pn_len; /* length of port numbers */
     struct descriptor_strings ds;
 };
 
@@ -206,6 +209,7 @@
 
 /* default options */
 static char opt_vendor[16]   = "";
+static char opt_search[64]   = "";     /* Search by attached device 
description */
 static char opt_location[32] = "";     /* Hub location a-b.c.d */
 static int opt_level = 0;              /* Hub location level (e.g., a-b is 
level 2, a-b.c is level 3)*/
 static int opt_ports  = ALL_HUB_PORTS; /* Bitmask of ports to operate on */
@@ -215,10 +219,12 @@
 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 const struct option long_options[] = {
     { "location", required_argument, NULL, 'l' },
     { "vendor",   required_argument, NULL, 'n' },
+    { "search",   required_argument, NULL, 's' },
     { "level",    required_argument, NULL, 'L' },
     { "ports",    required_argument, NULL, 'p' },
     { "action",   required_argument, NULL, 'a' },
@@ -226,6 +232,7 @@
     { "repeat",   required_argument, NULL, 'r' },
     { "wait",     required_argument, NULL, 'w' },
     { "exact",    no_argument,       NULL, 'e' },
+    { "force",    no_argument,       NULL, 'f' },
     { "reset",    no_argument,       NULL, 'R' },
     { "version",  no_argument,       NULL, 'v' },
     { "help",     no_argument,       NULL, 'h' },
@@ -236,7 +243,7 @@
 static int print_usage()
 {
     printf(
-        "uhubctl %s: utility to control USB port power for smart hubs.\n"
+        "uhubctl: utility to control USB port power for smart hubs.\n"
         "Usage: uhubctl [options]\n"
         "Without options, show status for all smart hubs.\n"
         "\n"
@@ -246,20 +253,23 @@
         "--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"
         "--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"
         "--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"
         "--help,     -h - print this text.\n"
         "\n"
-        "Send bugs and requests to: https://github.com/mvp/uhubctl\n";,
-        PROGRAM_VERSION,
+        "Send bugs and requests to: https://github.com/mvp/uhubctl\n";
+        "version: %s\n",
         strlen(opt_vendor) ? opt_vendor : "any",
         opt_delay,
         opt_repeat,
-        opt_wait
+        opt_wait,
+        PROGRAM_VERSION
     );
     return 0;
 }
@@ -385,9 +395,9 @@
         );
 
         if (len >= minlen) {
-            unsigned char port_numbers[MAX_HUB_CHAIN] = {0};
             info->dev     = dev;
             info->bcd_usb = bcd_usb;
+            info->super_speed = (bcd_usb >= USB_SS_BCD);
             info->nports  = uhd->bNbrPorts;
             snprintf(
                 info->vendor, sizeof(info->vendor),
@@ -397,14 +407,13 @@
             );
 
             /* Convert bus and ports array into USB location string */
-            int bus = libusb_get_bus_number(dev);
-            snprintf(info->location, sizeof(info->location), "%d", bus);
-            int pcount = get_port_numbers(dev, port_numbers, MAX_HUB_CHAIN);
-            info->level = pcount + 1;
+            info->bus = libusb_get_bus_number(dev);
+            snprintf(info->location, sizeof(info->location), "%d", info->bus);
+            info->pn_len = get_port_numbers(dev, info->port_numbers, 
sizeof(info->port_numbers));
             int k;
-            for (k=0; k<pcount; k++) {
+            for (k=0; k < info->pn_len; k++) {
                 char s[8];
-                snprintf(s, sizeof(s), "%s%d", k==0 ? "-" : ".", 
port_numbers[k]);
+                snprintf(s, sizeof(s), "%s%d", k==0 ? "-" : ".", 
info->port_numbers[k]);
                 strcat(info->location, s);
             }
 
@@ -434,10 +443,10 @@
                 }
                 libusb_free_bos_descriptor(bos);
 
-                /* Raspberry Pi 4 hack for USB3 root hub: */
+                /* Raspberry Pi 4B hack for USB3 root hub: */
                 if (strlen(info->container_id)==0 &&
                     strcasecmp(info->vendor, "1d6b:0003")==0 &&
-                    info->level==1 &&
+                    info->pn_len==0 &&
                     info->nports==4 &&
                     bcd_usb==USB_SS_BCD)
                 {
@@ -445,26 +454,18 @@
                 }
             }
 
-            info->ppps = 0;
             /* Logical Power Switching Mode */
             int lpsm = uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM;
             if (lpsm == HUB_CHAR_COMMON_LPSM && info->nports == 1) {
                 /* For 1 port hubs, ganged power switching is the same as 
per-port: */
                 lpsm = HUB_CHAR_INDV_PORT_LPSM;
             }
-            /* Raspberry Pi 4 reports inconsistent descriptors, override: */
+            /* Raspberry Pi 4B reports inconsistent descriptors, override: */
             if (lpsm == HUB_CHAR_COMMON_LPSM && strcasecmp(info->vendor, 
"2109:3431")==0) {
                 lpsm = HUB_CHAR_INDV_PORT_LPSM;
             }
-            /* Over-Current Protection Mode */
-            int ocpm = uhd->wHubCharacteristics[0] & HUB_CHAR_OCPM;
-            /* LPSM must be supported per-port, and OCPM per port or ganged */
-            if ((lpsm == HUB_CHAR_INDV_PORT_LPSM) &&
-                (ocpm == HUB_CHAR_INDV_PORT_OCPM ||
-                 ocpm == HUB_CHAR_COMMON_OCPM))
-            {
-                info->ppps = 1;
-            }
+            info->lpsm = lpsm;
+            rc = 0;
         } else {
             rc = len;
         }
@@ -522,7 +523,7 @@
     int rc;
     int id_vendor  = 0;
     int id_product = 0;
-    char ports[64]   = "";
+    char hub_specific[64] = "";
     struct libusb_device_descriptor desc;
     struct libusb_device_handle *devh = NULL;
     rc = libusb_get_device_descriptor(dev, &desc);
@@ -552,8 +553,16 @@
             struct hub_info info;
             rc = get_hub_info(dev, &info);
             if (rc == 0) {
-                snprintf(ports, sizeof(ports), ", USB %x.%02x, %d ports",
-                   info.bcd_usb >> 8, info.bcd_usb & 0xFF, info.nports);
+                const char * lpsm_type;
+                if (info.lpsm == HUB_CHAR_INDV_PORT_LPSM) {
+                    lpsm_type = "ppps";
+                } else if (info.lpsm == HUB_CHAR_COMMON_LPSM) {
+                    lpsm_type = "ganged";
+                } else {
+                    lpsm_type = "nops";
+                }
+                snprintf(hub_specific, sizeof(hub_specific), ", USB %x.%02x, 
%d ports, %s",
+                   info.bcd_usb >> 8, info.bcd_usb & 0xFF, info.nports, 
lpsm_type);
             }
         }
         libusb_close(devh);
@@ -564,7 +573,7 @@
         ds->vendor[0]  ? " " : "", ds->vendor,
         ds->product[0] ? " " : "", ds->product,
         ds->serial[0]  ? " " : "", ds->serial,
-        ports
+        hub_specific
     );
     return 0;
 }
@@ -581,17 +590,9 @@
     int port_status;
     struct libusb_device_handle * devh = NULL;
     int rc = 0;
-    int hub_bus;
-    int dev_bus;
-    unsigned char hub_pn[MAX_HUB_CHAIN];
-    unsigned char dev_pn[MAX_HUB_CHAIN];
-    int hub_plen;
-    int dev_plen;
     struct libusb_device *dev = hub->dev;
     rc = libusb_open(dev, &devh);
     if (rc == 0) {
-        hub_bus = libusb_get_bus_number(dev);
-        hub_plen = get_port_numbers(dev, hub_pn, sizeof(hub_pn));
         int port;
         for (port = 1; port <= hub->nports; port++) {
             if (portmask > 0 && (portmask & (1 << (port-1))) == 0) continue;
@@ -611,12 +612,15 @@
             struct libusb_device * udev;
             int i = 0;
             while ((udev = usb_devs[i++]) != NULL) {
+                uint8_t dev_bus;
+                uint8_t dev_pn[MAX_HUB_CHAIN];
+                int dev_plen;
                 dev_bus = libusb_get_bus_number(udev);
                 /* only match devices on the same bus: */
-                if (dev_bus != hub_bus) continue;
+                if (dev_bus != hub->bus) continue;
                 dev_plen = get_port_numbers(udev, dev_pn, sizeof(dev_pn));
-                if ((dev_plen == hub_plen + 1) &&
-                    (memcmp(hub_pn, dev_pn, hub_plen) == 0) &&
+                if ((dev_plen == hub->pn_len + 1) &&
+                    (memcmp(hub->port_numbers, dev_pn, hub->pn_len) == 0) &&
                     libusb_get_port_number(udev) == port)
                 {
                     rc = get_device_description(udev, &ds);
@@ -625,7 +629,7 @@
                 }
             }
 
-            if (hub->bcd_usb < USB_SS_BCD) {
+            if (!hub->super_speed) {
                 if (port_status == 0) {
                     printf(" off");
                 } else {
@@ -703,30 +707,63 @@
         rc = get_hub_info(dev, &info);
         if (rc) {
             perm_ok = 0; /* USB permission issue? */
+            continue;
         }
         get_device_description(dev, &info.ds);
-        if (info.ppps) { /* PPPS is supported */
-            if (hub_count < MAX_HUBS) {
-                info.actionable = 1;
-                if (strlen(opt_location) > 0) {
-                    if (strcasecmp(opt_location, info.location)) {
-                        info.actionable = 0;
-                    }
-                }
-                if (opt_level > 0) {
-                    if (opt_level != info.level) {
-                        info.actionable = 0;
-                    }
-                }
-                if (strlen(opt_vendor) > 0) {
-                    if (strncasecmp(opt_vendor, info.vendor, 
strlen(opt_vendor))) {
-                        info.actionable = 0;
+        if (info.lpsm != HUB_CHAR_INDV_PORT_LPSM && !opt_force) {
+            continue;
+        }
+        info.actionable = 1;
+        if (strlen(opt_search) > 0) {
+            /* Search by attached device description */
+            info.actionable = 0;
+            struct libusb_device * udev;
+            int k = 0;
+            while ((udev = usb_devs[k++]) != NULL) {
+                uint8_t dev_pn[MAX_HUB_CHAIN];
+                uint8_t dev_bus = libusb_get_bus_number(udev);
+                /* only match devices on the same bus: */
+                if (dev_bus != info.bus) continue;
+                int dev_plen = get_port_numbers(udev, dev_pn, sizeof(dev_pn));
+                if ((dev_plen == info.pn_len + 1) &&
+                    (memcmp(info.port_numbers, dev_pn, info.pn_len) == 0))
+                {
+                    struct descriptor_strings ds;
+                    bzero(&ds, sizeof(ds));
+                    rc = get_device_description(udev, &ds);
+                    if (rc != 0)
+                        break;
+                    if (strstr(ds.description, opt_search)) {
+                        info.actionable = 1;
+                        opt_ports &= 1 << (dev_pn[dev_plen-1] - 1);
+                        break;
                     }
                 }
-                memcpy(&hubs[hub_count], &info, sizeof(info));
-                hub_count++;
             }
         }
+        if (strlen(opt_location) > 0) {
+            if (strcasecmp(opt_location, info.location)) {
+                info.actionable = 0;
+            }
+        }
+        if (opt_level > 0) {
+            if (opt_level != info.pn_len + 1) {
+                info.actionable = 0;
+            }
+        }
+        if (strlen(opt_vendor) > 0) {
+            if (strncasecmp(opt_vendor, info.vendor, strlen(opt_vendor))) {
+                info.actionable = 0;
+            }
+        }
+        memcpy(&hubs[hub_count], &info, sizeof(info));
+        if (hub_count < MAX_HUBS) {
+            hub_count++;
+        } else {
+            /* That should be impossible - but we don't want to crash! */
+            fprintf(stderr, "Too many hubs!");
+            break;
+        }
     }
     if (!opt_exact) {
         /* Handle USB2/3 duality: */
@@ -737,7 +774,8 @@
             /* Must have non empty container ID: */
             if (strlen(hubs[i].container_id) == 0)
                 continue;
-            int match = -1;
+            int best_match = -1;
+            int best_score = -1;
             for (j=0; j<hub_count; j++) {
                 if (i==j)
                     continue;
@@ -745,8 +783,7 @@
                 /* Find hub which is USB2/3 dual to the hub above */
 
                 /* Hub and its dual must be different types: one USB2, another 
USB3: */
-                if ((hubs[i].bcd_usb < USB_SS_BCD) ==
-                    (hubs[j].bcd_usb < USB_SS_BCD))
+                if (hubs[i].super_speed == hubs[j].super_speed)
                     continue;
 
                 /* Must have non empty container ID: */
@@ -762,6 +799,14 @@
                  * We should do few more checks below if multiple such devices 
are present.
                  */
 
+                /* Hubs should have the same number of ports */
+                if (hubs[i].nports != hubs[j].nports) {
+                    /* Except for some weird hubs like Apple mini-dock (has 2 
usb2 + 1 usb3 ports) */
+                    if (hubs[i].nports + hubs[j].nports > 3) {
+                        continue;
+                    }
+                }
+
                 /* If serial numbers are both present, they must match: */
                 if ((strlen(hubs[i].ds.serial) > 0 && 
strlen(hubs[j].ds.serial) > 0) &&
                     strcmp(hubs[i].ds.serial, hubs[j].ds.serial) != 0)
@@ -769,18 +814,56 @@
                     continue;
                 }
 
-                /* Hubs should have the same number of ports: */
-                if (hubs[i].nports != hubs[j].nports)
-                    continue;
+                /* We have first possible candidate, but need to keep looking 
for better one */
 
-                /* Finally, we claim a match: */
-                match = j;
-                break;
+                if (best_score < 1) {
+                    best_score = 1;
+                    best_match = j;
+                }
+
+                /* Checks for various levels of USB2 vs USB3 path 
similarity... */
+
+                uint8_t* p1 = hubs[i].port_numbers;
+                uint8_t* p2 = hubs[j].port_numbers;
+                int l1 = hubs[i].pn_len;
+                int l2 = hubs[j].pn_len;
+                int s1 = hubs[i].super_speed;
+                int s2 = hubs[j].super_speed;
+
+                /* Check if port path is the same after removing top level 
(needed for M1 Macs): */
+                if (l1 >= 1 && l1 == l2 && memcmp(p1 + 1, p2 + 1, l1 - 1)==0) {
+                    if (best_score < 2) {
+                        best_score = 2;
+                        best_match = j;
+                    }
+                }
+
+                /* Raspberry Pi 4B hack (USB2 hub is one level deeper than 
USB3): */
+                if (l1 + s1 == l2 + s2 && l1 >= s2 && memcmp(p1 + s2, p2 + s1, 
l1 - s2)==0) {
+                    if (best_score < 3) {
+                        best_score = 3;
+                        best_match = j;
+                    }
+                }
+                /* Check if port path is exactly the same: */
+                if (l1 == l2 && memcmp(p1, p2, l1)==0) {
+                    if (best_score < 4) {
+                        best_score = 4;
+                        best_match = j;
+                    }
+                    /* Give even higher priority if `usb2bus + 1 == usb3bus` 
(Linux specific): */
+                    if (hubs[i].bus - s1 == hubs[j].bus - s2) {
+                        if (best_score < 5) {
+                            best_score = 5;
+                            best_match = j;
+                        }
+                    }
+                }
             }
-            if (match >= 0) {
-                if (!hubs[match].actionable) {
+            if (best_match >= 0) {
+                if (!hubs[best_match].actionable) {
                     /* Use 2 to signify that this is derived dual device */
-                    hubs[match].actionable = 2;
+                    hubs[best_match].actionable = 2;
                 }
             }
         }
@@ -789,10 +872,18 @@
     for (i=0; i<hub_count; i++) {
         if (!hubs[i].actionable)
             continue;
-        if (hubs[i].bcd_usb < USB_SS_BCD || opt_exact) {
+        if (!hubs[i].super_speed || opt_exact) {
             hub_phys_count++;
         }
     }
+#ifdef __gnu_linux__
+    if (perm_ok == 0 && geteuid() != 0) {
+        fprintf(stderr,
+            "There were permission problems while accessing USB.\n"
+            "Follow https://git.io/JIB2Z for a fix!\n"
+        );
+    }
+#endif
     if (perm_ok == 0 && hub_phys_count == 0) {
         return LIBUSB_ERROR_ACCESS;
     }
@@ -807,7 +898,7 @@
     int option_index = 0;
 
     for (;;) {
-        c = getopt_long(argc, argv, "l:L:n:a:p:d:r:w:hveR",
+        c = getopt_long(argc, argv, "l:L:n:a:p:d:r:w:s:hvefR",
             long_options, &option_index);
         if (c == -1)
             break;  /* no more options left */
@@ -830,6 +921,9 @@
         case 'n':
             strncpy(opt_vendor, optarg, sizeof(opt_vendor));
             break;
+        case 's':
+            strncpy(opt_search, optarg, sizeof(opt_search));
+            break;
         case 'p':
             if (!strcasecmp(optarg, "all")) { /* all ports is the default */
                 break;
@@ -855,6 +949,9 @@
         case 'r':
             opt_repeat = atoi(optarg);
             break;
+        case 'f':
+            opt_force = 1;
+            break;
         case 'e':
             opt_exact = 1;
             break;
@@ -908,23 +1005,11 @@
     rc = usb_find_hubs();
     if (rc <= 0) {
         fprintf(stderr,
-            "No compatible smart hubs detected%s%s!\n"
+            "No compatible devices detected%s%s!\n"
             "Run with -h to get usage info.\n",
             strlen(opt_location) ? " at location " : "",
             opt_location
         );
-#ifdef __gnu_linux__
-        if (rc < 0 && geteuid() != 0) {
-            fprintf(stderr,
-                "There were permission problems while accessing USB.\n"
-                "To fix this, run this tool as root using 'sudo uhubctl',\n"
-                "or add one or more udev rules like below\n"
-                "to file '/etc/udev/rules.d/52-usb.rules':\n"
-                "SUBSYSTEM==\"usb\", ATTR{idVendor}==\"2001\", MODE=\"0666\"\n"
-                "then run 'sudo udevadm trigger --attr-match=subsystem=usb'\n"
-            );
-        }
-#endif
         rc = 1;
         goto cleanup;
     }
@@ -966,8 +1051,8 @@
                 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].bcd_usb < USB_SS_BCD ? 
USB_PORT_STAT_POWER
-                                                                      : 
USB_SS_PORT_STAT_POWER;
+                        int power_mask = hubs[i].super_speed ? 
USB_SS_PORT_STAT_POWER
+                                                             : 
USB_PORT_STAT_POWER;
                         if (k == 0 && !(port_status & power_mask))
                             continue;
                         if (k == 1 && (port_status & power_mask))
@@ -993,7 +1078,7 @@
                     }
                 }
                 /* USB3 hubs need extra delay to actually turn off: */
-                if (k==0 && hubs[i].bcd_usb >= USB_SS_BCD)
+                if (k==0 && hubs[i].super_speed)
                     sleep_ms(150);
                 printf("Sent power %s request\n",
                     request == LIBUSB_REQUEST_CLEAR_FEATURE ? "off" : "on"
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/[email protected]

Reply via email to