The Raspberry Pi 3 Model B+ has 4 USB ports and an ethernet port. In our application we will be using a USB sound card to sample a hydrophone. But when not in use the sound card will need powering down to save battery energy. At the moment the sound card uses around 1.4W when powered up.

A number of resources and forum discussions centred around power cycling USB ports on other Raspberry Pi editions. The hub-ctrl.c software does allow us to control the power of the USB ports on the RPi3B+, however, the internal configuration of the ports and how they are addressed is not quite as simple as A-D corresponding to ports 1-4 on a hub as we shall see below.

USB Hierarchy

Listing the usb devices shows all the ports as “bus-port.port.port…port:config.interface”. More information about this can be found at linux-usb.org.

$ ls /sys/bus/usb/devices/ 
1-0:1.0 1-1 1-1.1 1-1:1.0 1-1.1.1 1-1.1:1.0 1-1.1.1:1.0 usb1

Here we can see Bus01 with ports and sub-ports. If we now list the usb tree structure using lsusb we see the root hub, with a 4 port hub (hub/4p), which then holds a 3 port hub (hub/3p), and finally the Ethernet LAN driver chip.

$ lsusb -t 
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M

Connecting a sound card to each of the USB ports in turn, and printing the USB device tree shows each of the following.

Raspberry Pi 3 Model B+ Ethernet and USB ports labelled.

Connected to USB A:

$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 2: Dev 7, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 5, Class=Human Interface Device, Driver=usbhid, 12M

Connected to USB B:

$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 3: Dev 8, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 5, Class=Human Interface Device, Driver=usbhid, 12M

Connected to USB C:

$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 2: Dev 9, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 5, Class=Human Interface Device, Driver=usbhid, 12M

Connected to USB D:

$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 3: Dev 10, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 5, Class=Human Interface Device, Driver=usbhid, 12M

Based on the original usb device listings (“bus-port.port.port…port”) the following table describes each of the ports:

  • Eth0: 1-1.1.1.1
  • USB A: 1-1.1.1.2
  • USB B: 1-1.1.1.3
  • USB C: 1-1.1.2
  • USB D: 1-1.1.3

hub-ctrl.c

First we compile the hub-ctrl.c as per the instructions in the readme.

Checking how hub-ctrl labels the respective usb hubs (4 port, and 3 port) we use the command as follows:

$ sudo ./hub-ctrl -v
Hub #0 at 001:003
INFO: individual power switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect
Port 2: 0000.0100 power
Port 3: 0000.0100 power
Hub #1 at 001:002
INFO: individual power switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect
Port 2: 0000.0100 power
Port 3: 0000.0103 power enable connect
Port 4: 0000.0100 power
Hub #2 at 001:001
INFO: ganged switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect

In this case, the 4 port hub is labelled as hub #1 by hub-ctrl.

So using hub-ctrl.c as per the instructions in the readme. We can switch off the power to USB D as follows:

$ sudo ./hub-ctrl -h 1 -P 3 -p 0

This command needs to be sent twice in quick succession to keep the sound card switched off. Otherwise, it re-powers up after one second. Not sure why at this stage, but will explore further.

The power can then be brought back on to USB D with the simple change:

$ sudo ./hub-ctrl -h 1 -P 3 -p 1

Other Raspberry Pi versions and models may well have different USB port configurations, the above approach should allow us to discover the setup on any new devices.